You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2020/09/09 11:08:54 UTC

[isis] branch master updated: ISIS-2426: tooling: adds project tree (modeling)

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new 5d2468c  ISIS-2426: tooling: adds project tree (modeling)
5d2468c is described below

commit 5d2468c4feaa4afe55b89f8c24a0eeef048282d5
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Sep 9 13:08:36 2020 +0200

    ISIS-2426: tooling: adds project tree (modeling)
---
 tooling/project-model/pom.xml                      |  18 +-
 .../isis/tooling/projectmodel/ProjectNode.java     |  46 +++++
 .../tooling/projectmodel/ProjectNodeFactory.java   | 116 +++++++++++++
 .../isis/tooling/projectmodel/ProjectVisitor.java  |  27 +++
 .../projectmodel/maven/MavenModelFactory.java      |  99 +++++++++++
 .../projectmodel/maven/SimpleModelResolver.java    | 190 +++++++++++++++++++++
 .../project-model/src/main/resources/log4j2.xml    |  16 ++
 .../tooling/projectmodel/test/ProjectTreeTest.java |  71 ++++++++
 8 files changed, 582 insertions(+), 1 deletion(-)

diff --git a/tooling/project-model/pom.xml b/tooling/project-model/pom.xml
index f08923e..8f4d7b1 100644
--- a/tooling/project-model/pom.xml
+++ b/tooling/project-model/pom.xml
@@ -19,7 +19,7 @@
 		<artifactId>isis-tooling</artifactId>
 		<version>2.0.0-SNAPSHOT</version>
 	</parent>
-	
+
 	<artifactId>isis-tooling-project-model</artifactId>
 
 	<name>Apache Isis Tooling - Project Model</name>
@@ -31,6 +31,22 @@
 	</properties>
 
 	<dependencies>
+
+		<dependency>
+			<groupId>org.apache.isis.tooling</groupId>
+			<artifactId>isis-tooling-commons</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.gradle</groupId>
+			<artifactId>gradle-tooling-api</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.maven</groupId>
+			<artifactId>maven-model-builder</artifactId>
+		</dependency>
+
 	</dependencies>
 
 </project>
diff --git a/tooling/project-model/src/main/java/org/apache/isis/tooling/projectmodel/ProjectNode.java b/tooling/project-model/src/main/java/org/apache/isis/tooling/projectmodel/ProjectNode.java
new file mode 100644
index 0000000..5de56d3
--- /dev/null
+++ b/tooling/project-model/src/main/java/org/apache/isis/tooling/projectmodel/ProjectNode.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.tooling.projectmodel;
+
+import java.util.TreeSet;
+
+import lombok.Builder;
+import lombok.Data;
+import lombok.ToString;
+import lombok.val;
+
+@Data @Builder
+public class ProjectNode {
+
+    @ToString.Exclude private final ProjectNode parent;
+    @ToString.Exclude private final TreeSet<ProjectNode> children = new TreeSet<ProjectNode>(
+            (a,b)->a.getArtifactId().compareTo(b.getArtifactId()));
+    
+    private final String artifactId;
+    private final String name;
+    private final String description;
+    
+    public void depthFirst(ProjectVisitor projectVisitor) {
+        projectVisitor.accept(this);
+        for(val child : getChildren()){
+            child.depthFirst(projectVisitor);
+        }
+    }
+
+}
diff --git a/tooling/project-model/src/main/java/org/apache/isis/tooling/projectmodel/ProjectNodeFactory.java b/tooling/project-model/src/main/java/org/apache/isis/tooling/projectmodel/ProjectNodeFactory.java
new file mode 100644
index 0000000..a4ec7ab
--- /dev/null
+++ b/tooling/project-model/src/main/java/org/apache/isis/tooling/projectmodel/ProjectNodeFactory.java
@@ -0,0 +1,116 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.tooling.projectmodel;
+
+import java.io.File;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import org.apache.maven.model.Model;
+import org.gradle.tooling.GradleConnector;
+import org.gradle.tooling.model.GradleProject;
+
+import org.apache.isis.tooling.projectmodel.maven.MavenModelFactory;
+import org.apache.isis.tooling.projectmodel.maven.SimpleModelResolver;
+
+import lombok.val;
+
+public class ProjectNodeFactory {
+
+    public static ProjectNode maven(File projRootFolder) {
+        val modelResolver = new SimpleModelResolver(projRootFolder);
+        val rootModel = modelResolver.getRootModel();
+        val interpolate = false; //XXX experimental
+        return visitMavenProject(null, rootModel, modelResolver, interpolate);
+    }
+
+    public static ProjectNode gradle(File projRootFolder) {
+        try(val projectConnection = GradleConnector.newConnector().forProjectDirectory(projRootFolder).connect()) {
+            val rootProject = projectConnection.getModel(GradleProject.class);
+            val rootNode = visitGradleProject(null, rootProject);
+            return rootNode;
+        } 
+    }
+
+    // -- HELPER MAVEN
+
+    private static ProjectNode visitMavenProject(
+            ProjectNode parent, 
+            Model mavenProj, 
+            SimpleModelResolver modelResolver,
+            boolean interpolate) {
+        
+        val interpolatedProj = interpolate 
+                ? MavenModelFactory.interpolateModel(mavenProj, modelResolver)
+                : mavenProj;
+        val projNode = toProjectNode(parent, interpolatedProj);
+        for(val child : childrenOf(interpolatedProj, modelResolver)){
+            visitMavenProject(projNode, child, modelResolver, interpolate);
+        }
+        return projNode;
+    }
+    
+    private static ProjectNode toProjectNode(ProjectNode parent, Model mavenProj) {
+        val projNode = ProjectNode.builder()
+                .parent(parent)
+                .artifactId(mavenProj.getArtifactId())
+                .name(mavenProj.getName())
+                .build();
+
+        if(parent!=null) {
+            parent.getChildren().add(projNode);
+        }
+
+        return projNode;
+
+    }
+    
+    private static Iterable<Model> childrenOf(Model mavenProj, SimpleModelResolver modelResolver) {
+        return mavenProj.getModules()
+        .stream()
+        .map(name->modelResolver.lookupCatalogForSubmoduleOf(mavenProj, name))
+        .filter(Objects::nonNull)
+        .collect(Collectors.toList());
+    }
+    
+    // -- HELPER GRADLE
+    
+    private static ProjectNode visitGradleProject(ProjectNode parent, GradleProject gradleProj) {
+        val projNode = toProjectNode(parent, gradleProj);
+        for(val child : gradleProj.getChildren()){
+            visitGradleProject(projNode, child);
+        }
+        return projNode;
+    }
+
+    private static ProjectNode toProjectNode(ProjectNode parent, GradleProject gradleProj) {
+        val projNode = ProjectNode.builder()
+                .parent(parent)
+                .artifactId(gradleProj.getProjectIdentifier().getProjectPath())
+                .name(gradleProj.getName())
+                .build();
+        if(parent!=null) {
+            parent.getChildren().add(projNode);
+        }
+        return projNode;
+    }
+
+
+
+}
diff --git a/tooling/project-model/src/main/java/org/apache/isis/tooling/projectmodel/ProjectVisitor.java b/tooling/project-model/src/main/java/org/apache/isis/tooling/projectmodel/ProjectVisitor.java
new file mode 100644
index 0000000..54dffff
--- /dev/null
+++ b/tooling/project-model/src/main/java/org/apache/isis/tooling/projectmodel/ProjectVisitor.java
@@ -0,0 +1,27 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.tooling.projectmodel;
+
+import java.util.function.Consumer;
+
+public interface ProjectVisitor extends Consumer<ProjectNode> {
+    
+    
+
+}
diff --git a/tooling/project-model/src/main/java/org/apache/isis/tooling/projectmodel/maven/MavenModelFactory.java b/tooling/project-model/src/main/java/org/apache/isis/tooling/projectmodel/maven/MavenModelFactory.java
new file mode 100644
index 0000000..2c8f003
--- /dev/null
+++ b/tooling/project-model/src/main/java/org/apache/isis/tooling/projectmodel/maven/MavenModelFactory.java
@@ -0,0 +1,99 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.tooling.projectmodel.maven;
+
+import java.io.File;
+import java.io.FileReader;
+import java.util.Optional;
+
+import org.apache.maven.model.Model;
+import org.apache.maven.model.building.DefaultModelBuilderFactory;
+import org.apache.maven.model.building.DefaultModelBuildingRequest;
+import org.apache.maven.model.building.ModelBuildingException;
+import org.apache.maven.model.building.ModelBuildingRequest;
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.model.resolution.ModelResolver;
+
+import lombok.val;
+import lombok.experimental.UtilityClass;
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+@UtilityClass
+public class MavenModelFactory {
+    
+    public static Model interpolateModel(final Model model, final ModelResolver modelResolver) {
+        
+        val pomFile = model.getPomFile();
+        
+        log.info("interpolating model {}", pomFile);
+        
+        val modelBuildRequest = new DefaultModelBuildingRequest()
+        .setProcessPlugins(false)
+        .setPomFile(pomFile)
+        .setModelResolver(modelResolver)
+        .setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
+
+        try {
+            val modelBuilder = new DefaultModelBuilderFactory().newInstance();
+            return modelBuilder.build(modelBuildRequest).getEffectiveModel();
+        } catch (ModelBuildingException e) {
+             log.warn("maven model interpolation failed {}", pomFile, e);
+             //throw new RuntimeException(String.format("maven model building failed %s", pomFile), e);
+        }
+        
+        // fallback to non interpolated
+        return model;
+        
+    }
+    
+
+    /** non interpolated read */
+    public static Model readModel(File pomFile) {
+        val reader = new MavenXpp3Reader();
+        try {
+            val model =  reader.read(new FileReader(pomFile));
+            model.setPomFile(pomFile);
+            return model;
+        } catch (Exception e) {
+            log.error("failed to read {}", pomFile.getAbsolutePath(), e);
+            throw new RuntimeException(String.format("failed to read %s", pomFile.getAbsolutePath()), e);
+        }
+    }
+    
+    public static String readArtifactKey(Model model) {
+        if(model==null) {
+            return null;
+        }
+        val artifactKey = String.format("%s:%s:%s", 
+                getGroupId(model), 
+                model.getArtifactId(), 
+                getVersion(model));
+        return artifactKey;
+    }
+    
+    private static String getGroupId(Model model) {
+        return Optional.ofNullable(model.getGroupId()).orElseGet(()->model.getParent().getGroupId());
+    }
+    
+    private static String getVersion(Model model) {
+        return Optional.ofNullable(model.getVersion()).orElseGet(()->model.getParent().getVersion());
+    }
+    
+}
diff --git a/tooling/project-model/src/main/java/org/apache/isis/tooling/projectmodel/maven/SimpleModelResolver.java b/tooling/project-model/src/main/java/org/apache/isis/tooling/projectmodel/maven/SimpleModelResolver.java
new file mode 100644
index 0000000..c7309ae
--- /dev/null
+++ b/tooling/project-model/src/main/java/org/apache/isis/tooling/projectmodel/maven/SimpleModelResolver.java
@@ -0,0 +1,190 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.tooling.projectmodel.maven;
+
+import java.io.File;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Parent;
+import org.apache.maven.model.Repository;
+import org.apache.maven.model.building.FileModelSource;
+import org.apache.maven.model.building.ModelSource;
+import org.apache.maven.model.building.UrlModelSource;
+import org.apache.maven.model.resolution.InvalidRepositoryException;
+import org.apache.maven.model.resolution.ModelResolver;
+import org.apache.maven.model.resolution.UnresolvableModelException;
+
+import org.apache.isis.tooling._infra._Files;
+
+import lombok.Getter;
+import lombok.SneakyThrows;
+import lombok.val;
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+public class SimpleModelResolver implements ModelResolver {
+    
+    //non interpolated models
+    private final Map<String, Model> projectPomCatalog = new HashMap<>();
+    private final Map<String, String> pathToArtifactMap = new HashMap<>();
+    private final Map<String, Repository> repositories = new LinkedHashMap<>();
+    
+    @Getter private Model rootModel;
+    
+    public SimpleModelResolver(final File projectRoot) {
+        populateCatalogs(projectRoot);
+    }
+
+    @Override
+    public ModelSource resolveModel(String groupId, String artifactId, String version)
+            throws UnresolvableModelException {
+        
+        val key = String.format("%s:%s:%s", groupId, artifactId, version);
+        
+        log.info("resolveModel {}", key);
+        
+        try {
+
+            val pomModel = projectPomCatalog.get(key);
+            if(pomModel!=null) {
+                return new FileModelSource(pomModel.getPomFile());    
+            }
+            
+            if(repositories.size()==0) {
+                throw new RuntimeException("no repo registered");
+            }
+            
+            for(val entry : repositories.entrySet()) {
+                val repo = entry.getValue();
+                
+                val pomUrl = new URL(String.format("%s/%s/%s/%s/%s-%s.pom",
+                        repo.getUrl(),
+                        groupId.replace('.', '/'), 
+                        artifactId, 
+                        version,
+                        artifactId, 
+                        version));
+                
+                try {
+                    val urlConn = pomUrl.openConnection();
+                    val is = urlConn.getInputStream(); // throws if not found
+                    is.close();
+                    return new UrlModelSource(pomUrl);
+                } catch (Exception e) {
+                    // try next
+                }
+            }
+            
+            log.warn("No repo found that serves {}", key);
+            
+            throw new RuntimeException(String.format("No repo found that serves %s", key));
+            
+        } catch (Exception ex) {
+            throw new UnresolvableModelException(ex.getMessage(), groupId, artifactId, version);
+        }
+    }
+
+    @Override
+    public ModelSource resolveModel(Parent parent) throws UnresolvableModelException {
+        log.info("resolveModel-parent");
+        return resolveModel(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
+    }
+
+    @Override
+    public ModelSource resolveModel(Dependency dependency) throws UnresolvableModelException {
+        log.info("resolveModel-dependency");
+        return resolveModel(
+                dependency.getGroupId(), 
+                dependency.getArtifactId(),
+                dependency.getVersion());
+    }
+
+    @Override
+    public void addRepository(Repository repository) throws InvalidRepositoryException {
+        log.info("adding repository {}", repository.getUrl());
+        repositories.put(repository.getId(), repository);
+    }
+
+    @Override
+    public void addRepository(Repository repository, boolean replace) throws InvalidRepositoryException {
+        addRepository(repository);
+    }
+
+    @Override
+    public ModelResolver newCopy() {
+        return this;
+    }
+    
+    public Model lookupCatalogForSubmoduleOf(Model mavenProj, String name) {
+        
+        val localPath = new File(mavenProj.getPomFile().getParentFile(), name)
+                .getAbsolutePath();
+        
+        val artifactKey = pathToArtifactMap.get(localPath);
+        if(artifactKey==null) {
+            return null;
+        }
+        
+        val subProj = projectPomCatalog.get(artifactKey);
+        if(subProj==null) {
+            return null;
+        }
+        return subProj;
+    }
+    
+    @SneakyThrows
+    private void populateCatalogs(final File projectRoot) {
+        
+        val localRootPath = projectRoot.getAbsolutePath();
+        
+        _Files.searchFiles(projectRoot, 
+                file->!"target".equals(file.getName()), 
+                file->"pom.xml".equals(file.getName()))
+        .stream()
+        .forEach(pomFile->{
+            
+            val model = MavenModelFactory.readModel(pomFile);
+            
+            val localPath = pomFile.getParentFile().getAbsolutePath();
+            
+            if(localPath.equals(localRootPath)) {
+                rootModel = model;
+            }
+            
+            val artifactKey = MavenModelFactory.readArtifactKey(model);
+            if(artifactKey!=null) {
+                log.debug("found {} at {}", artifactKey, model.getPomFile().getAbsolutePath());
+                projectPomCatalog.put(artifactKey, model);    
+                pathToArtifactMap.put(localPath, artifactKey);
+            }
+        });
+    }
+
+
+
+
+    
+}
diff --git a/tooling/project-model/src/main/resources/log4j2.xml b/tooling/project-model/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..5cea1c5
--- /dev/null
+++ b/tooling/project-model/src/main/resources/log4j2.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="warn">
+    <Appenders>
+        <Console name="console" target="SYSTEM_OUT">
+            <PatternLayout   pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n" />
+        </Console>
+    </Appenders>
+    <Loggers>
+        <Logger name="org.apache.isis.tooling" level="info" additivity="true">
+            <appender-ref ref="console" />
+        </Logger>
+        <Root level="warn" additivity="false">
+            <appender-ref ref="console" />
+        </Root>
+    </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/tooling/project-model/src/test/java/org/apache/isis/tooling/projectmodel/test/ProjectTreeTest.java b/tooling/project-model/src/test/java/org/apache/isis/tooling/projectmodel/test/ProjectTreeTest.java
new file mode 100644
index 0000000..e2efec0
--- /dev/null
+++ b/tooling/project-model/src/test/java/org/apache/isis/tooling/projectmodel/test/ProjectTreeTest.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.tooling.projectmodel.test;
+
+import java.io.File;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import org.apache.isis.tooling.projectmodel.ProjectNodeFactory;
+import org.apache.isis.tooling.projectmodel.ProjectVisitor;
+
+import lombok.val;
+
+class ProjectTreeTest {
+    
+    File projRootFolder;
+    
+    @BeforeEach
+    void setUp() throws Exception {
+        projRootFolder = new File("./").getAbsoluteFile().getParentFile().getParentFile().getParentFile();
+        System.out.println("running ProjectTreeTest at " + projRootFolder.getAbsolutePath());
+    }
+
+    @AfterEach
+    void tearDown() throws Exception {
+    }
+
+    @Test
+    void testGradle() {
+        
+        val projTree = ProjectNodeFactory.gradle(projRootFolder);
+        
+        ProjectVisitor projectVisitor = projModel -> {System.out.println(projModel);};
+        
+        projTree.depthFirst(projectVisitor);
+        
+    }
+    
+    @Test
+    void testMaven() {
+        
+        val projTree = ProjectNodeFactory.maven(projRootFolder);
+        
+        ProjectVisitor projectVisitor = projModel -> {System.out.println(projModel);};
+        
+        projTree.depthFirst(projectVisitor);
+        
+      
+        
+    }
+
+
+}