use of org.eclipse.core.resources.IWorkspaceRunnable in project generator by mybatis.
the class WorkspaceUtilities method createJavaProject.
static IJavaProject createJavaProject(final String projectName, final String[] sourceFolders, final String projectOutput, final String compliance) throws CoreException {
final IJavaProject[] result = new IJavaProject[1];
IWorkspaceRunnable create = new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
// create project
createProject(projectName);
// set java nature
addJavaNature(projectName);
// create classpath entries
IProject project = getWorkspaceRoot().getProject(projectName);
IPath projectPath = project.getFullPath();
int sourceLength = sourceFolders == null ? 0 : sourceFolders.length;
IClasspathEntry[] entries = new IClasspathEntry[sourceLength];
for (int i = 0; i < sourceLength; i++) {
IPath sourcePath = new Path(sourceFolders[i]);
int segmentCount = sourcePath.segmentCount();
if (segmentCount > 0) {
// create folder and its parents
IContainer container = project;
for (int j = 0; j < segmentCount; j++) {
IFolder folder = container.getFolder(new Path(sourcePath.segment(j)));
if (!folder.exists()) {
folder.create(true, true, null);
}
container = folder;
}
}
// create source entry
entries[i] = JavaCore.newSourceEntry(projectPath.append(sourcePath));
}
// create project's output folder
IPath outputPath = new Path(projectOutput);
if (outputPath.segmentCount() > 0) {
IFolder output = project.getFolder(outputPath);
if (!output.exists()) {
output.create(true, true, monitor);
}
}
// set classpath and output location
IJavaProject javaProject = JavaCore.create(project);
javaProject.setRawClasspath(entries, projectPath.append(outputPath), monitor);
// set compliance level options
if ("1.5".equals(compliance)) {
Map<String, String> options = new HashMap<String, String>();
options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_5);
options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_5);
options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_5);
javaProject.setOptions(options);
} else if ("1.6".equals(compliance)) {
Map<String, String> options = new HashMap<String, String>();
options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_6);
options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6);
options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_6);
javaProject.setOptions(options);
} else if ("1.7".equals(compliance)) {
Map<String, String> options = new HashMap<String, String>();
options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7);
options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7);
options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7);
javaProject.setOptions(options);
} else if ("1.8".equals(compliance)) {
Map<String, String> options = new HashMap<String, String>();
options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8);
options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8);
options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8);
javaProject.setOptions(options);
}
result[0] = javaProject;
}
};
getWorkspace().run(create, null);
return result[0];
}
use of org.eclipse.core.resources.IWorkspaceRunnable in project tdi-studio-se by Talend.
the class UpdateManagerUtils method doExecuteUpdates.
private static boolean doExecuteUpdates(final List<UpdateResult> results, final boolean updateAllJobs) {
if (results == null || results.isEmpty()) {
return false;
}
try {
IWorkspaceRunnable op = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
monitor.setCanceled(false);
int size = (results.size() * 2 + 1) * UpdatesConstants.SCALE;
//$NON-NLS-1$
monitor.beginTask(Messages.getString("UpdateManagerUtils.Update"), size);
ProxyRepositoryFactory factory = ProxyRepositoryFactory.getInstance();
// first list by job we need to update
Map<String, Set<String>> jobIdToVersion = new HashMap<String, Set<String>>();
Map<String, Boolean> jobIdClosed = new HashMap<String, Boolean>();
for (UpdateResult result : results) {
// if (!result.isChecked()) {
// continue;
// }
String id = result.getObjectId();
String version = result.getObjectVersion();
if (id == null) {
if (result.getJob() != null && result.getJob() instanceof IProcess) {
IProcess process = (IProcess) result.getJob();
if (process instanceof IProcess2 && ERepositoryStatus.LOCK_BY_OTHER.equals(factory.getStatus(((IProcess2) process).getProperty().getItem()))) {
// file.
continue;
}
id = process.getId();
version = process.getVersion();
result.setObjectId(id);
result.setObjectVersion(version);
} else {
continue;
}
}
Set<String> versionList;
if (!jobIdToVersion.containsKey(id)) {
versionList = new HashSet<String>();
jobIdToVersion.put(id, versionList);
} else {
versionList = jobIdToVersion.get(id);
}
versionList.add(version);
//$NON-NLS-1$
jobIdClosed.put(id + " - " + version, result.isFromItem());
}
// now will execute updates only for the job selected depends this list.
for (String currentId : jobIdToVersion.keySet()) {
for (String version : jobIdToVersion.get(currentId)) {
IRepositoryViewObject currentObj = null;
//$NON-NLS-1$
boolean closedItem = jobIdClosed.get(currentId + " - " + version);
IProcess process = null;
Item item = null;
if (closedItem) {
// if item is closed, then just load it.
boolean checkOnlyLastVersion = Boolean.parseBoolean(DesignerPlugin.getDefault().getPreferenceStore().getString(//$NON-NLS-1$
"checkOnlyLastVersion"));
try {
if (checkOnlyLastVersion || version == null) {
currentObj = factory.getLastVersion(currentId);
} else {
List<IRepositoryViewObject> allVersion = factory.getAllVersion(currentId);
for (IRepositoryViewObject obj : allVersion) {
if (obj.getVersion().equals(version)) {
currentObj = obj;
}
}
}
} catch (PersistenceException e) {
ExceptionHandler.process(e);
}
if (currentObj == null) {
// item not found, don't do anything
continue;
}
item = currentObj.getProperty().getItem();
IDesignerCoreService designerCoreService = CorePlugin.getDefault().getDesignerCoreService();
if (item instanceof ProcessItem) {
process = designerCoreService.getProcessFromProcessItem((ProcessItem) item);
} else if (item instanceof JobletProcessItem) {
process = designerCoreService.getProcessFromJobletProcessItem((JobletProcessItem) item);
}
}
for (UpdateResult result : results) {
// }
if (!StringUtils.equals(currentId, result.getObjectId())) {
// not the current job we need to update
continue;
}
if (closedItem) {
if (result.getJob() == null) {
result.setJob(process);
} else {
process = (IProcess) result.getJob();
}
IUpdateItemType jobletContextType = UpdateManagerProviderDetector.INSTANCE.getUpdateItemType(UpdateManagerHelper.TYPE_JOBLET_CONTEXT);
if (process != null && jobletContextType != null && (jobletContextType.equals(result.getUpdateType()))) {
if ((result.getParameter() instanceof List) && process.getContextManager() != null) {
process.getContextManager().setListContext((List<IContext>) result.getParameter());
}
}
}
// execute
executeUpdate(result, monitor, updateAllJobs);
if (closedItem) {
result.setJob(null);
}
}
boolean isTestContainer = false;
ITestContainerProviderService testContainerService = null;
if (GlobalServiceRegister.getDefault().isServiceRegistered(ITestContainerProviderService.class)) {
testContainerService = (ITestContainerProviderService) GlobalServiceRegister.getDefault().getService(ITestContainerProviderService.class);
if (testContainerService != null) {
isTestContainer = testContainerService.isTestContainerItem(item);
}
}
if (closedItem && process instanceof IProcess2) {
IProcess2 process2 = (IProcess2) process;
ProcessType processType;
try {
processType = process2.saveXmlFile(false);
if (isTestContainer) {
testContainerService.setTestContainerProcess(processType, item);
} else if (item instanceof JobletProcessItem) {
((JobletProcessItem) item).setJobletProcess((JobletProcess) processType);
} else {
((ProcessItem) item).setProcess(processType);
}
factory.save(item);
} catch (IOException e) {
ExceptionHandler.process(e);
} catch (PersistenceException e) {
ExceptionHandler.process(e);
}
}
if (closedItem && !ERepositoryStatus.LOCK_BY_USER.equals(factory.getStatus(item))) {
// unload item from memory, but only if this one is not locked by current user.
try {
factory.unloadResources(item.getProperty());
} catch (PersistenceException e) {
ExceptionHandler.process(e);
}
}
}
}
UpdateManagerProviderDetector.INSTANCE.postUpdate(results);
// update joblet reference
upadateJobletReferenceInfor();
final List<UpdateResult> tempResults = new ArrayList<UpdateResult>(results);
// refresh
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
refreshRelatedViewers(tempResults);
// hyWang add method checkandRefreshProcess for bug7248
checkandRefreshProcess(tempResults);
}
});
monitor.worked(1 * UpdatesConstants.SCALE);
monitor.done();
}
};
IRunnableWithProgress iRunnableWithProgress = new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
try {
ISchedulingRule schedulingRule = workspace.getRoot();
workspace.run(op, schedulingRule, IWorkspace.AVOID_UPDATE, monitor);
} catch (CoreException e) {
throw new InvocationTargetException(e);
}
}
};
try {
new ProgressMonitorDialog(null).run(false, false, iRunnableWithProgress);
} catch (InvocationTargetException e) {
ExceptionHandler.process(e);
} catch (InterruptedException e) {
}
return !results.isEmpty();
} finally {
results.clear();
}
}
use of org.eclipse.core.resources.IWorkspaceRunnable in project tdi-studio-se by Talend.
the class BuildJobManager method buildJob.
public void buildJob(String destinationPath, ProcessItem itemToExport, String version, String context, Map<ExportChoice, Object> exportChoiceMap, JobExportType jobExportType, boolean checkCompilationError, IProgressMonitor monitor) throws Exception {
IProgressMonitor pMonitor = new NullProgressMonitor();
if (monitor != null) {
pMonitor = monitor;
}
final boolean oldMeasureActived = TimeMeasure.measureActive;
if (!oldMeasureActived) {
// not active before.
TimeMeasure.display = TimeMeasure.displaySteps = TimeMeasure.measureActive = CommonsPlugin.isDebugMode();
}
final String timeMeasureId = "Build job for " + itemToExport.getProperty().getLabel() + ' ' + version;
TimeMeasure.begin(timeMeasureId);
try {
final int scale = 1000;
int total = 4;
//$NON-NLS-1$
pMonitor.beginTask(Messages.getString("JobScriptsExportWizardPage.newExportJobScript", jobExportType), scale * total);
ProcessItem processItem = itemToExport;
// get correct version
if (!RelationshipItemBuilder.LATEST_VERSION.equals(version) && version != null && !"".equals(version) && !version.equals(processItem.getProperty().getVersion())) {
processItem = ItemCacheManager.getProcessItem(processItem.getProperty().getId(), version);
}
final String label = processItem.getProperty().getLabel();
final IBuildJobHandler buildJobHandler = BuildJobFactory.createBuildJobHandler(processItem, context, version, exportChoiceMap, jobExportType);
ProcessUtils.setJarWithContext(ProcessUtils.needsToHaveContextInsideJar(processItem));
final IWorkspaceRunnable op = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor wrMonitor) throws CoreException {
try {
wrMonitor.beginTask(Messages.getString("JobScriptsExportWizardPage.newExportJobScript", jobExportType), scale * 3);
TimeMeasure.step(timeMeasureId, "prepare to build job");
buildJobHandler.generateItemFiles(true, new SubProgressMonitor(wrMonitor, scale));
wrMonitor.worked(scale);
TimeMeasure.step(timeMeasureId, "generateItemFiles");
buildJobHandler.generateJobFiles(new SubProgressMonitor(wrMonitor, scale));
wrMonitor.worked(scale);
TimeMeasure.step(timeMeasureId, "generateJobFiles");
buildJobHandler.build(new SubProgressMonitor(wrMonitor, scale));
TimeMeasure.step(timeMeasureId, "build and package");
wrMonitor.done();
} catch (Exception e) {
throw new CoreException(new org.eclipse.core.runtime.Status(IStatus.ERROR, FrameworkUtil.getBundle(this.getClass()).getSymbolicName(), "Error", e));
}
}
;
};
IWorkspace workspace = ResourcesPlugin.getWorkspace();
try {
ISchedulingRule schedulingRule = workspace.getRoot();
// the update the project files need to be done in the workspace runnable to avoid all
// notification
// of changes before the end of the modifications.
workspace.run(op, schedulingRule, IWorkspace.AVOID_UPDATE, pMonitor);
} catch (CoreException e) {
Throwable cause = e.getCause();
if (cause == null) {
throw new PersistenceException(e);
}
throw new PersistenceException(cause);
}
ProcessUtils.setJarWithContext(false);
IFile jobTargetFile = buildJobHandler.getJobTargetFile();
if (jobTargetFile != null && jobTargetFile.exists()) {
IPath jobZipLocation = jobTargetFile.getLocation();
File jobZipFile = jobZipLocation.toFile();
String jobZip = jobZipLocation.toString();
if (needClasspathJar(exportChoiceMap)) {
ExportJobUtil.deleteTempFiles();
JavaJobExportReArchieveCreator creator = new JavaJobExportReArchieveCreator(jobZip, label);
FilesUtils.unzip(jobZip, creator.getTmpFolder() + File.separator + label + "_" + version);
creator.buildNewJar();
ZipToFile.zipFile(creator.getTmpFolder(), jobZip);
creator.deleteTempFiles();
TimeMeasure.step(timeMeasureId, "Recreate job jar for classpath");
}
// TBD-2500
Set<ProcessItem> processItems = new HashSet<ProcessItem>();
processItems.add(processItem);
// We get the father job childs.
Set<JobInfo> infos = ProcessorUtilities.getChildrenJobInfo(processItem);
Iterator<JobInfo> infoIterator = infos.iterator();
while (infoIterator.hasNext()) {
processItems.add(infoIterator.next().getProcessItem());
}
TimeMeasure.step(timeMeasureId, "getChildrenJobInfo");
// We iterate over the job and its childs in order to re-archive them if needed.
for (ProcessItem pi : processItems) {
BDJobReArchieveCreator bdRecreator = new BDJobReArchieveCreator(pi, processItem);
bdRecreator.create(jobZipFile);
}
TimeMeasure.step(timeMeasureId, "BDJobReArchieveCreator");
File jobFileTarget = new File(destinationPath);
if (jobFileTarget.isDirectory()) {
jobFileTarget = new File(destinationPath, jobZipFile.getName());
}
FilesUtils.copyFile(jobZipFile, jobFileTarget);
TimeMeasure.step(timeMeasureId, "Copy packaged file to target");
} else if (jobTargetFile != null) {
throw new Exception("Job was not built successfully, please check the logs for more details available on the workspace/.Java/lastGenerated.log");
}
if (checkCompilationError) {
CorePlugin.getDefault().getRunProcessService().checkLastGenerationHasCompilationError(false);
}
pMonitor.worked(scale);
pMonitor.done();
} finally {
TimeMeasure.end(timeMeasureId);
// if active before, not disable and active still.
if (!oldMeasureActived) {
TimeMeasure.display = TimeMeasure.displaySteps = TimeMeasure.measureActive = false;
}
}
}
use of org.eclipse.core.resources.IWorkspaceRunnable in project tdi-studio-se by Talend.
the class ImportItemUtil method importItemRecords.
@SuppressWarnings("unchecked")
public List<ItemRecord> importItemRecords(final ResourcesManager manager, final List<ItemRecord> itemRecords, final IProgressMonitor monitor, final boolean overwrite, final IPath destinationPath, final String contentType) {
TimeMeasure.display = CommonsPlugin.isDebugMode();
TimeMeasure.displaySteps = CommonsPlugin.isDebugMode();
TimeMeasure.measureActive = CommonsPlugin.isDebugMode();
TimeMeasure.begin("importItemRecords");
hasJoblets = false;
statAndLogsSettingsReloaded = false;
implicitSettingsReloaded = false;
restoreFolder = new RestoreFolderUtil();
Collections.sort(itemRecords, new Comparator<ItemRecord>() {
@Override
public int compare(ItemRecord o1, ItemRecord o2) {
if (o1.getProperty().getItem() instanceof RoutineItem && o2.getProperty().getItem() instanceof RoutineItem) {
return 0;
} else if (!(o1.getProperty().getItem() instanceof RoutineItem) && !(o2.getProperty().getItem() instanceof RoutineItem)) {
// TUP-2548 sort items by label
String label = o1.getLabel();
if (label == null) {
return -1;
}
final String label2 = o2.getLabel();
if (label2 == null) {
return 1;
}
return label.compareTo(label2);
} else if (o1.getProperty().getItem() instanceof RoutineItem) {
return -1;
} else {
return 1;
}
}
});
//$NON-NLS-1$
monitor.beginTask(Messages.getString("ImportItemWizardPage.ImportSelectedItems"), itemRecords.size() * 2 + 1);
RepositoryWorkUnit repositoryWorkUnit = new //$NON-NLS-1$
RepositoryWorkUnit(//$NON-NLS-1$
"Import Items") {
@Override
public void run() throws PersistenceException {
final IWorkspaceRunnable op = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
final IProxyRepositoryFactory factory = CorePlugin.getDefault().getProxyRepositoryFactory();
// bug 10520
final Set<String> overwriteDeletedItems = new HashSet<String>();
final Set<String> idDeletedBeforeImport = new HashSet<String>();
Map<String, String> nameToIdMap = new HashMap<String, String>();
for (ItemRecord itemRecord : itemRecords) {
if (!monitor.isCanceled()) {
if (itemRecord.isValid()) {
if (itemRecord.getState() == State.ID_EXISTED) {
String id = nameToIdMap.get(itemRecord.getProperty().getLabel() + ERepositoryObjectType.getItemType(itemRecord.getProperty().getItem()).toString());
if (id == null) {
/*
* if id exsist then need to genrate new id for this job,in this case the
* job won't override the old one
*/
id = EcoreUtil.generateUUID();
nameToIdMap.put(itemRecord.getProperty().getLabel() + ERepositoryObjectType.getItemType(itemRecord.getProperty().getItem()).toString(), id);
}
itemRecord.getProperty().setId(id);
}
}
}
}
for (ItemRecord itemRecord : itemRecords) {
if (!monitor.isCanceled()) {
if (itemRecord.isValid()) {
importItemRecord(manager, itemRecord, overwrite, destinationPath, overwriteDeletedItems, idDeletedBeforeImport, contentType, monitor);
IRepositoryViewObject object;
try {
Property property = itemRecord.getProperty();
if (property == null) {
object = factory.getSpecificVersion(itemRecord.getItemId(), itemRecord.getItemVersion(), true);
property = object.getProperty();
}
RelationshipItemBuilder.getInstance().addOrUpdateItem(property.getItem(), true);
itemRecord.setProperty(null);
ProxyRepositoryFactory.getInstance().unloadResources(property);
} catch (PersistenceException e) {
ExceptionHandler.process(e);
}
statAndLogsSettingsReloaded = false;
implicitSettingsReloaded = false;
monitor.worked(1);
}
}
}
// deploy routines Jar
if (!getRoutineExtModulesMap().isEmpty()) {
Set<String> extRoutines = new HashSet<String>();
for (String id : getRoutineExtModulesMap().keySet()) {
Set<String> set = getRoutineExtModulesMap().get(id);
if (set != null) {
extRoutines.addAll(set);
}
}
if (manager instanceof ProviderManager || manager instanceof ZipFileManager) {
deployJarToDesForArchive(manager, extRoutines);
} else {
deployJarToDes(manager, extRoutines);
}
}
if (PluginChecker.isJobLetPluginLoaded()) {
IJobletProviderService service = (IJobletProviderService) GlobalServiceRegister.getDefault().getService(IJobletProviderService.class);
if (service != null) {
service.loadComponentsFromProviders();
}
}
checkDeletedFolders();
monitor.done();
TimeMeasure.step("importItemRecords", "before save");
if (RelationshipItemBuilder.getInstance().isNeedSaveRelations()) {
RelationshipItemBuilder.getInstance().saveRelations();
TimeMeasure.step("importItemRecords", "save relations");
} else {
// with relations
try {
factory.saveProject(ProjectManager.getInstance().getCurrentProject());
} catch (PersistenceException e) {
throw new CoreException(new Status(IStatus.ERROR, FrameworkUtil.getBundle(this.getClass()).getSymbolicName(), "Import errors", e));
}
TimeMeasure.step("importItemRecords", "save project");
}
}
};
IWorkspace workspace = ResourcesPlugin.getWorkspace();
try {
ISchedulingRule schedulingRule = workspace.getRoot();
// the update the project files need to be done in the workspace runnable to avoid all
// notification
// of changes before the end of the modifications.
workspace.run(op, schedulingRule, IWorkspace.AVOID_UPDATE, monitor);
} catch (CoreException e) {
// ?
}
}
};
repositoryWorkUnit.setAvoidUnloadResources(true);
repositoryWorkUnit.setUnloadResourcesAfterRun(true);
ProxyRepositoryFactory.getInstance().executeRepositoryWorkUnit(repositoryWorkUnit);
monitor.done();
// for (ItemRecord itemRecord : itemRecords) {
// itemRecord.clear();
// }
clearAllData();
if (hasJoblets) {
ComponentsFactoryProvider.getInstance().resetSpecificComponents();
}
TimeMeasure.end("importItemRecords");
TimeMeasure.display = false;
TimeMeasure.displaySteps = false;
TimeMeasure.measureActive = false;
return itemRecords;
}
use of org.eclipse.core.resources.IWorkspaceRunnable in project tesb-studio-se by Talend.
the class OpenAnotherVersionResrouceWizard method performFinish.
@Override
public boolean performFinish() {
if (mainPage.isCreateNewVersionJob()) {
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
public void run(final IProgressMonitor monitor) throws CoreException {
if (!alreadyEditedByUser) {
getProperty().setVersion(mainPage.getNewVersion());
refreshNewJob();
try {
ProxyRepositoryFactory.getInstance().saveProject(ProjectManager.getInstance().getCurrentProject());
} catch (PersistenceException e) {
ExceptionHandler.process(e);
}
}
try {
ProxyRepositoryFactory.getInstance().lock(repoObject);
} catch (PersistenceException | LoginException e) {
ExceptionHandler.process(e);
}
// boolean locked = repoObject.getRepositoryStatus().equals(
// ERepositoryStatus.LOCK_BY_USER);
openAnotherVersion((IRepositoryNode) repoObject.getRepositoryNode());
try {
ProxyRepositoryFactory.getInstance().saveProject(ProjectManager.getInstance().getCurrentProject());
} catch (PersistenceException e) {
ExceptionHandler.process(e);
}
}
};
IWorkspace workspace = ResourcesPlugin.getWorkspace();
try {
ISchedulingRule schedulingRule = workspace.getRoot();
// the update the project files need to be done in the workspace
// runnable to avoid all notification
// of changes before the end of the modifications.
workspace.run(runnable, schedulingRule, IWorkspace.AVOID_UPDATE, null);
} catch (CoreException e) {
MessageBoxExceptionHandler.process(e);
}
} else {
StructuredSelection selection = (StructuredSelection) mainPage.getSelection();
IRepositoryNode node = (IRepositoryNode) selection.getFirstElement();
boolean lastVersion = node.getObject().getVersion().equals(repoObject.getVersion());
repoObject.getProperty().setVersion(originalVersion);
if (lastVersion) {
lockObject(repoObject);
}
// ERepositoryStatus status = node.getObject().getRepositoryStatus();
// boolean isLocked = false;
// if (status == ERepositoryStatus.LOCK_BY_USER) {
// isLocked = true;
// }
// Only latest version can be editted
openAnotherVersion(node);
}
return true;
}
Aggregations