alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 *
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 *
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.modules.ant.freeform.ui;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.netbeans.api.java.platform.JavaPlatform;
import org.netbeans.modules.ant.freeform.FreeformProject;
import org.netbeans.modules.ant.freeform.FreeformProjectGenerator;
import org.netbeans.spi.project.AuxiliaryConfiguration;
import org.netbeans.spi.project.support.ant.AntProjectHelper;
import org.netbeans.spi.project.support.ant.PropertyEvaluator;
import org.netbeans.spi.project.support.ant.PropertyUtils;
import org.openide.filesystems.FileUtil;

// TODO: refactor target mappings panel (and other project settings) to also use ProjectModel

/**
 * Memory model of project. Used for creation or customization of project.
 *
 * @author David Konecny
 */
public class ProjectModel  {
    
    /** Original project base folder */
    private File baseFolder;
    
    /** Freeform Project base folder */
    private File nbProjectFolder;

    private PropertyEvaluator evaluator;
    
    private String sourceLevel;
    
    /** List of FreeformProjectGenerator.SourceFolders instances of type "java". */
    private List/**/ sourceFolders;
    
    /** List of  */
    public List/**/ javaCompilationUnitsList;

    private Set/**/ addedSourceFolders;
    private Set/**/ removedSourceFolders;
    
    public static final String TYPE_JAVA = "java"; // NOI18N
    public static final String STYLE_PACKAGES = "packages"; // NOI18N
    public static final String CLASSPATH_MODE_COMPILE = "compile"; // NOI18N
    
    private ProjectModel(File baseFolder, File nbProjectFolder, PropertyEvaluator evaluator, List sourceFolders, List compUnits) {
        this.baseFolder = baseFolder;
        this.nbProjectFolder = nbProjectFolder;
        this.evaluator = evaluator;
        this.sourceFolders = sourceFolders;
        this.javaCompilationUnitsList = compUnits;
        if (javaCompilationUnitsList.size() > 0) {
            sourceLevel = ((FreeformProjectGenerator.JavaCompilationUnit)javaCompilationUnitsList.get(0)).sourceLevel;
        }
        if (sourceLevel == null) {
            setSourceLevel(getDefaultSourceLevel());
        }
        resetState();
    }
    
    private void resetState() {
        addedSourceFolders = new HashSet();
        removedSourceFolders = new HashSet();
    }

    /** Create empty project model. Useful for new project creation. */
    public static ProjectModel createEmptyModel(File baseFolder, File nbProjectFolder, PropertyEvaluator evaluator) {
        return new ProjectModel(baseFolder, nbProjectFolder, evaluator, new ArrayList(), new ArrayList());
    }

    /** Create project model of existing project. Useful for project customization. */
    public static ProjectModel createModel(FreeformProject project, AntProjectHelper helper) {
        ProjectModel pm = new ProjectModel(
                FreeformProjectGenerator.getProjectLocation(project), 
                FileUtil.toFile(project.getProjectDirectory()), 
                project.evaluator(),
                // reads only "java" type because other types are not editable in UI
                FreeformProjectGenerator.getSourceFolders(helper, TYPE_JAVA),
                FreeformProjectGenerator.getJavaCompilationUnits(helper,
                    FreeformProjectGenerator.getAuxiliaryConfiguration(helper))
            );
        // only "java" type of sources was read so fix style to "pacakges" on all
        updateStyle(pm.sourceFolders);
        return pm;
    }

    /** Instantiate project model as new Java project. */
    public static void instantiateJavaProject(ProjectModel model, String projName, File antScript, List mappings) throws IOException {
        List sourceFolders = model.updatePrincipalSourceFolders(model.sourceFolders, true);
        FreeformProjectGenerator.createJavaProject(model.getBaseFolder(), model.getNBProjectFolder(), projName, antScript, mappings, sourceFolders, model.javaCompilationUnitsList);
        model.resetState();
    }
    
    /** Instantiate project model as new Web project. */
    public static void instantiateWebProject(ProjectModel model, String projName, File antScript, List mappings, List webModules) throws IOException {
        List sourceFolders = model.updatePrincipalSourceFolders(model.sourceFolders, true);
        FreeformProjectGenerator.createWebProject(model.getBaseFolder(), model.getNBProjectFolder(), projName, antScript, mappings, sourceFolders, model.javaCompilationUnitsList, webModules);
        model.resetState();
    }

    /** Persist modifications of project. */
    public static void saveProject(AntProjectHelper helper, ProjectModel model) {
        // stores only "java" type because other types was not read
        FreeformProjectGenerator.putSourceFolders(helper, model.sourceFolders, TYPE_JAVA);
        FreeformProjectGenerator.putSourceViews(helper, model.sourceFolders, STYLE_PACKAGES);
        
        List sourceFolders = FreeformProjectGenerator.getSourceFolders(helper, null);
        sourceFolders = model.updatePrincipalSourceFolders(sourceFolders, false);
        FreeformProjectGenerator.putSourceFolders(helper, sourceFolders, null);

        AuxiliaryConfiguration aux = FreeformProjectGenerator.getAuxiliaryConfiguration(helper);
        FreeformProjectGenerator.putJavaCompilationUnits(helper, aux, model.javaCompilationUnitsList);
        model.resetState();
    }

    /**
     * This method according to the state of removed/added source folders
     * will ensure that all added typed external source roots will have
     * corresponding principal source folder and that principal source
     * folders of all removed typed external source roots are removed too.
     * In addition it can add project base folder as principal root 
     * if it is external.
     *
     * It is expected that this method will be called before project instantiation
     * or before update of project's data. 
     *
     * @param allSourceFolders list of all source folders, i.e. typed and untyped.
     * @param checkProjectDir should project base folder be checked
     * and added as principal source folder if needed or not
     * @return copy of allSourceFolders items plus added principal source folders
     */
    /*private*/ List/**/ updatePrincipalSourceFolders(
            List/**/ allSourceFolders, boolean checkProjectDir) {
        List allSF = new ArrayList(allSourceFolders);
        Iterator it = addedSourceFolders.iterator();
        while (it.hasNext()) {
            String location = (String)it.next();
            
            if (!isExternalSourceRoot(location)) {
                continue;
            }
            
            boolean exist = false;
            String label = ""; // NOI18N
            Iterator it2 = allSF.iterator();
            while (it2.hasNext()) {
                FreeformProjectGenerator.SourceFolder _sf = (FreeformProjectGenerator.SourceFolder)it2.next();
                if (_sf.location.equals(location) && _sf.type == null) {
                    exist = true;
                    break;
                }
                if (_sf.location.equals(location) && _sf.type != null) {
                    // find some label to use
                    label = _sf.label;
                }
            }
            
            if (!exist) {
                FreeformProjectGenerator.SourceFolder _sf = new FreeformProjectGenerator.SourceFolder();
                _sf.location = location;
                _sf.label = label;
                allSF.add(_sf);
            }
        }
        
        it = removedSourceFolders.iterator();
        while (it.hasNext()) {
            String location = (String)it.next();
            
            if (!isExternalSourceRoot(location)) {
                continue;
            }
            
            Iterator it2 = allSF.iterator();
            while (it2.hasNext()) {
                FreeformProjectGenerator.SourceFolder _sf = (FreeformProjectGenerator.SourceFolder)it2.next();
                if (_sf.location.equals(location) && _sf.type == null) {
                    it2.remove();
                }
            }
        }
        
        if (checkProjectDir && !baseFolder.equals(nbProjectFolder)) {
            FreeformProjectGenerator.SourceFolder gen = new FreeformProjectGenerator.SourceFolder();
            gen.location = "${"+FreeformProjectGenerator.PROP_PROJECT_LOCATION+"}"; // NOI18N
            // XXX: uniquefy label
            gen.label = baseFolder.getName();
            allSF.add(gen);
        }
        
        return allSF;
    }

    private boolean isExternalSourceRoot(String location) {
        String baseFolder_ = baseFolder.getAbsolutePath();
        if (!baseFolder_.endsWith(File.separator)) {
            baseFolder_ += File.separatorChar;
        }
        String nbProjectFolder_ = nbProjectFolder.getAbsolutePath();
        if (!nbProjectFolder_.endsWith(File.separator)) {
            nbProjectFolder_ += File.separatorChar;
        }
        location = FreeformProjectGenerator.resolveFile(evaluator, baseFolder, location);
        return (!location.startsWith(baseFolder_) &&
                    !location.startsWith(nbProjectFolder_));
    }
    
    /** Original project base folder. */
    public File getBaseFolder() {
        return baseFolder;
    }
    
    /** NetBeans project folder. */
    public File getNBProjectFolder() {
        return nbProjectFolder;
    }
    
    public PropertyEvaluator getEvaluator() {
        return evaluator;
    }
    
    public int getSourceFoldersCount() {
        return sourceFolders.size();
    }
    
    public FreeformProjectGenerator.SourceFolder getSourceFolder(int index) {
        return (FreeformProjectGenerator.SourceFolder)sourceFolders.get(index);
    }
    
    public void addSourceFolder(FreeformProjectGenerator.SourceFolder sf) {
        List keys = createCompilationUnitKeys();
        boolean singleCU = isSingleCompilationUnit(keys);
        sourceFolders.add(sf);
        if (singleCU) {
            if (TYPE_JAVA.equals(sf.type)) {
                // update existing single compilation unit
                FreeformProjectGenerator.JavaCompilationUnit cu = (FreeformProjectGenerator.JavaCompilationUnit)javaCompilationUnitsList.get(0);
                cu.packageRoots.add(sf.location);
            }
        } else {
            // make sure new compilation unit is created for the source folder
            Iterator it = createCompilationUnitKeys().iterator();
            while (it.hasNext()) {
                CompilationUnitKey key = (CompilationUnitKey)it.next();
                getCompilationUnit(key);
            }
        }
        // remember all added locations
        if (removedSourceFolders.contains(sf.location)) {
            removedSourceFolders.remove(sf.location);
        } else {
            addedSourceFolders.add(sf.location);
        }
    }

    public void removeSourceFolder(int index) {
        FreeformProjectGenerator.SourceFolder sf = (FreeformProjectGenerator.SourceFolder)sourceFolders.get(index);
        if (TYPE_JAVA.equals(sf.type)) {
            removeSourceLocation(sf.location);
        }
        sourceFolders.remove(index);
        // remember all removed locations
        if (addedSourceFolders.contains(sf.location)) {
            addedSourceFolders.remove(sf.location);
        } else {
            removedSourceFolders.add(sf.location);
        }
    }
    
    public void clearSourceFolders() {
        sourceFolders.clear();
        javaCompilationUnitsList.clear();
    }
    
    public String getSourceLevel() {
        return sourceLevel;
    }

    public void setSourceLevel(String sourceLevel) {
        if ((this.sourceLevel == null && sourceLevel == null) ||
            (this.sourceLevel != null && this.sourceLevel.equals(sourceLevel))) {
            return;
        }
        this.sourceLevel = sourceLevel;
        Iterator it = javaCompilationUnitsList.iterator();
        while (it.hasNext()) {
            FreeformProjectGenerator.JavaCompilationUnit cu = (FreeformProjectGenerator.JavaCompilationUnit)it.next();
            cu.sourceLevel = sourceLevel;
        }
    }
    
    public boolean canHaveSeparateClasspath() {
        // if there is more than one source root or more than one
        // compilation unit then enable checkbox "Separate Classpath".
        return (sourceFolders.size() > 1 || javaCompilationUnitsList.size() > 1);
    }

    public static boolean isSingleCompilationUnit(List/**/ compilationUnitKeys) {
        return compilationUnitKeys.size() == 1 &&
            ((ProjectModel.CompilationUnitKey)compilationUnitKeys.get(0)).label == null;
    }

    /**
     * This methos checks Java source foldes and compilation units and returns 
     * list of CompilationUnitKey which represent them. The problem solved by
     * this method is that although usually there is 1:1 mapping between
     * source folders and copilation units, there can be also N:1 mapping when
     * one classpath is used for all source folders. Also user's customization
     * of project.xml can result in other combinations and they cannot be
     * clobbered by opening such a project in UI.
     */
    public List/**/ createCompilationUnitKeys() {
        // XXX: cache result of this method?
        ArrayList l = new ArrayList();
        Iterator it = javaCompilationUnitsList.iterator();
        while (it.hasNext()) {
            FreeformProjectGenerator.JavaCompilationUnit cu = (FreeformProjectGenerator.JavaCompilationUnit)it.next();
            CompilationUnitKey cul = new CompilationUnitKey();
            cul.locations = cu.packageRoots;
            cul.label = null;
            l.add(cul);
        }
        it = sourceFolders.iterator();
        while (it.hasNext()) {
            FreeformProjectGenerator.SourceFolder sf = (FreeformProjectGenerator.SourceFolder)it.next();
            if (!TYPE_JAVA.equals(sf.type)) {
                continue;
            }
            CompilationUnitKey cul = new CompilationUnitKey();
            cul.locations = new ArrayList();
            cul.locations.add(sf.location);
            cul.label = sf.label;
            // try to find corresponding JavaCompilationUnit
            int index = l.indexOf(cul);
            if (index != -1) {
                // use this key intead because it has label
                CompilationUnitKey cul_ = (CompilationUnitKey)l.get(index);
                cul_.label = sf.label;
                continue;
            }
            // check whether this SourceFolder.location is not part of an existing JavaCompilationUnit
            boolean found = false;
            Iterator it2 = javaCompilationUnitsList.iterator();
            while (it2.hasNext()) {
                FreeformProjectGenerator.JavaCompilationUnit cu_ = (FreeformProjectGenerator.JavaCompilationUnit)it2.next();
                if (cu_.packageRoots.contains(sf.location)) {
                    // found: skip it
                    found = true;
                    break;
                }
            }
            if (found) {
                continue;
            }
            // add this source folder then:
            l.add(cul);
        }
        return l;
    }

    /**
     * Update compilation units to 1:1 or 1:N mapping to source folders.
     * The separateClasspath attribute if true says that each source folder
     * will have its own compilation unit. In opposite case all source
     * folders will have one compilation unit.
     */
    public void updateCompilationUnits(boolean separateClasspath) {
        if (separateClasspath) {
            // This means that there was one compilation unit for all sources.
            // So create compilation unit per source folder.
            String classpath = null;
            List output = null;
            // Copy classpath and output from the first compilation unit
            // to all compilation units - should be easier to customize for user.
            if (javaCompilationUnitsList.size() > 0) {
                List classpaths = ((FreeformProjectGenerator.JavaCompilationUnit)javaCompilationUnitsList.get(0)).classpath;
                if (classpaths != null) {
                    // find first "compile" mode classpath and use it
                    Iterator it = classpaths.iterator();
                    while (it.hasNext()) {
                        FreeformProjectGenerator.JavaCompilationUnit.CP cp = (FreeformProjectGenerator.JavaCompilationUnit.CP)it.next();
                        if (cp.mode.equals(CLASSPATH_MODE_COMPILE)) {
                            classpath = cp.classpath;
                            break;
                        }
                    }
                }
                output = ((FreeformProjectGenerator.JavaCompilationUnit)javaCompilationUnitsList.get(0)).output;
            }
            javaCompilationUnitsList.clear();
            Iterator it = sourceFolders.iterator();
            while (it.hasNext()) {
                FreeformProjectGenerator.SourceFolder sf = (FreeformProjectGenerator.SourceFolder)it.next();
                FreeformProjectGenerator.JavaCompilationUnit cu = new FreeformProjectGenerator.JavaCompilationUnit();
                cu.packageRoots = new ArrayList();
                cu.packageRoots.add(sf.location);
                if (classpath != null) {
                    FreeformProjectGenerator.JavaCompilationUnit.CP cp = new FreeformProjectGenerator.JavaCompilationUnit.CP();
                    cp.mode = CLASSPATH_MODE_COMPILE;
                    cp.classpath = classpath;
                    cu.classpath = new ArrayList();
                    cu.classpath.add(cp);
                }
                if (output != null) {
                    cu.output = new ArrayList();
                    cu.output.addAll(output);
                }
                cu.sourceLevel = sourceLevel;
                javaCompilationUnitsList.add(cu);
            }
        } else {
            // This means that there are some compilation units which should be
            // merged into one which will be used for all sources.
            List packageRoots = new ArrayList();
            // First list of source roots
            Iterator it = sourceFolders.iterator();
            while (it.hasNext()) {
                FreeformProjectGenerator.SourceFolder sf = (FreeformProjectGenerator.SourceFolder)it.next();
                packageRoots.add(sf.location);
            }
            // Now try to merge all classpaths and outputs. Might be easier to customize
            Set classpath = new LinkedHashSet();
            Set output = new LinkedHashSet();
            it = javaCompilationUnitsList.iterator();
            while (it.hasNext()) {
                FreeformProjectGenerator.JavaCompilationUnit cu = (FreeformProjectGenerator.JavaCompilationUnit)it.next();
                if (cu.output != null) {
                    output.addAll(cu.output);
                }
                if (cu.classpath != null) {
                    Iterator it2 = cu.classpath.iterator();
                    while (it2.hasNext()) {
                        FreeformProjectGenerator.JavaCompilationUnit.CP cp = (FreeformProjectGenerator.JavaCompilationUnit.CP)it2.next();
                        if (cp.mode.equals(CLASSPATH_MODE_COMPILE)) {
                            String[] cpa = PropertyUtils.tokenizePath(cp.classpath);
                            for (int i=0; i 0) {
                StringBuffer cp_ = new StringBuffer();
                it = classpath.iterator();
                while (it.hasNext()) {
                    String item = (String)it.next();
                    cp_.append(item);
                    if (it.hasNext()) {
                        cp_.append(File.pathSeparatorChar);
                    }
                }
                cp.classpath = cp_.toString();
                cp.mode = CLASSPATH_MODE_COMPILE;
                cu.classpath = new ArrayList();
                cu.classpath.add(cp);
            }
            cu.output = new ArrayList(output);
            cu.sourceLevel = sourceLevel;
            javaCompilationUnitsList.add(cu);
        }
    }

    /** Retrieve compilation unit or create empty one if it does not exist yet for the given 
     * key which is source package path(s).*/
    public FreeformProjectGenerator.JavaCompilationUnit getCompilationUnit(CompilationUnitKey key) {
        Iterator it = javaCompilationUnitsList.iterator();
        while (it.hasNext()) {
            FreeformProjectGenerator.JavaCompilationUnit cu = (FreeformProjectGenerator.JavaCompilationUnit)it.next();
            if (cu.packageRoots.equals(key.locations)) {
                return cu;
            }
        }
        FreeformProjectGenerator.JavaCompilationUnit cu = new FreeformProjectGenerator.JavaCompilationUnit();
        cu.packageRoots = key.locations;
        cu.sourceLevel = sourceLevel;
        javaCompilationUnitsList.add(cu);
        return cu;
    }

    private void removeSourceLocation(String location) {
        Iterator it = javaCompilationUnitsList.iterator();
        while (it.hasNext()) {
            FreeformProjectGenerator.JavaCompilationUnit cu = (FreeformProjectGenerator.JavaCompilationUnit)it.next();
            if (cu.packageRoots.contains(location)) {
                cu.packageRoots.remove(location);
            }
            if (cu.packageRoots.size() == 0) {
                it.remove();
            }
        }
    }

    /** Update style of loaded source folders of type "java" to packages. */
    private static void updateStyle(List/**/ sources) {
        Iterator it = sources.iterator();
        while (it.hasNext()) {
            FreeformProjectGenerator.SourceFolder sf = (FreeformProjectGenerator.SourceFolder)it.next();
            assert sf.type.equals(TYPE_JAVA);
            sf.style = STYLE_PACKAGES;
        }
    }
    
    // only for unit testing
    void setSourceFolders(List list) {
        sourceFolders = list;
    }
    
    // only for unit testing
    List getSourceFolders() {
        return sourceFolders;
    }
    
    // only for unit testing
    void setJavaCompilationUnits(List list) {
        javaCompilationUnitsList = list;
    }
    
    // only for unit testing
    List getJavaCompilationUnits() {
        return javaCompilationUnitsList;
    }
    
    
    /**
     * Helper method returning source level of the current platform.
     */
    public static String getDefaultSourceLevel() {
        JavaPlatform platform = JavaPlatform.getDefault();
        return platform.getSpecification().getVersion().toString();
    }
    
    static class CompilationUnitKey {
        public List locations;
        public String label;
        
        public boolean equals(Object o) {
            if (o == this) {
                return true;
            }
            if (!(o instanceof CompilationUnitKey)) {
                return false;
            }
            CompilationUnitKey cul = (CompilationUnitKey)o;
            return this.locations.equals(cul.locations);
        }
        
        public int hashCode() {
            return locations.hashCode()*7;
        }

        public String toString() {
            return "PM.CUK:[label="+label+", locations="+locations+", this="+super.toString()+"]"; // NOI18N
        }
    }
    
    
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.