blob: d2833a371ded41c16d6bfe1b21ff872beffb74b0 [file] [log] [blame]
/*
* 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.netbeans.modules.java.j2semodule;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.java.platform.JavaPlatform;
import org.netbeans.api.java.project.JavaProjectConstants;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.api.queries.FileEncodingQuery;
import org.netbeans.modules.java.api.common.project.ProjectProperties;
import org.netbeans.spi.project.support.ant.AntProjectHelper;
import org.netbeans.spi.project.support.ant.EditableProperties;
import org.netbeans.spi.project.support.ant.ProjectGenerator;
import org.netbeans.spi.project.support.ant.PropertyUtils;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.modules.SpecificationVersion;
import org.openide.util.Exceptions;
import org.openide.util.Mutex;
import org.openide.util.MutexException;
import org.openide.util.NbBundle;
import org.openide.util.Parameters;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Creates a J2SEModularProject from scratch according to some initial configuration.
*/
public class J2SEModularProjectGenerator {
private static final String DEFAULT_PLATFORM_ID = "default_platform"; //NOI18N
private static final String PROP_PLATFORM_ANT_NAME = "platform.ant.name"; //NOI18N
private static final String METRICS_LOGGER = "org.netbeans.ui.metrics.projects"; //NOI18N
private static final String J2SE_MODULAR_METRICS_LOGGER = "org.netbeans.ui.metrics.j2se-modular"; //NOI18N
enum Action {
CREATE("USG_PROJECT_CREATE", "USG_PROJECT_CREATE_J2SE_MODULAR"), //NOI18N
OPEN("USG_PROJECT_OPEN", "USG_PROJECT_OPEN_J2SE_MODULAR"), //NOI18N
CLOSE("USG_PROJECT_CLOSE", "USG_PROJECT_CLOSE_J2SE_MODULAR"); //NOI18N
private final String genericLogMessage;
private final String specificLogMessage;
private Action(
@NonNull final String genericLogMessage,
@NonNull final String specificLogMessage) {
assert genericLogMessage != null;
assert specificLogMessage != null;
this.genericLogMessage = genericLogMessage;
this.specificLogMessage = specificLogMessage;
}
@NonNull
public String getGenericLogMessage() {
return genericLogMessage;
}
@NonNull
public String getSpecificLogMessage() {
return specificLogMessage;
}
}
private J2SEModularProjectGenerator() {}
/**
* Create a new empty J2SE modular project.
* @param dir the top-level directory (need not yet exist but if it does it must be empty)
* @param name the name for the project
* @return the helper object permitting it to be further customized
* @throws IOException in case something went wrong
*/
public static AntProjectHelper createProject(final File dir, final String name, final JavaPlatform platform) throws IOException {
Parameters.notNull("dir", dir); //NOI18N
Parameters.notNull("name", name); //NOI18N
final FileObject dirFO = FileUtil.createFolder(dir);
final AntProjectHelper[] h = new AntProjectHelper[1];
dirFO.getFileSystem().runAtomicAction(() -> {
final SpecificationVersion sourceLevel = getSourceLevel(platform);
h[0] = createProject(dirFO, name, sourceLevel, "src", "classes", "tests", platform.getProperties().get(PROP_PLATFORM_ANT_NAME)); //NOI18N
final J2SEModularProject p = (J2SEModularProject) ProjectManager.getDefault().findProject(dirFO);
ProjectManager.getDefault().saveProject(p);
try {
ProjectManager.mutex().writeAccess((Mutex.ExceptionAction<Void>) () -> {
ProjectManager.getDefault().saveProject (p);
ProjectUtils.getSources(p).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_MODULES);
return null;
});
} catch (MutexException ex) {
Exceptions.printStackTrace(ex.getException());
}
dirFO.createFolder("src"); //NOI18N
});
return h[0];
}
private static AntProjectHelper createProject(
FileObject dirFO,
String name,
SpecificationVersion sourceLevel,
String srcRoot,
String srcRootPath,
String testSrcRootPath,
@NonNull final String platformId
) throws IOException {
final String antName = PropertyUtils.getUsablePropertyName(name);
AntProjectHelper h = ProjectGenerator.createProject(dirFO, J2SEModularProject.TYPE);
Element data = h.getPrimaryConfigurationData(true);
Document doc = data.getOwnerDocument();
Element nameEl = doc.createElementNS(J2SEModularProject.PROJECT_CONFIGURATION_NAMESPACE, "name"); // NOI18N
nameEl.appendChild(doc.createTextNode(name));
data.appendChild(nameEl);
EditableProperties ep = h.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
if (!DEFAULT_PLATFORM_ID.equals(platformId)) {
final Element platformEl = doc.createElementNS(J2SEModularProject.PROJECT_CONFIGURATION_NAMESPACE, "explicit-platform"); //NOI18N
platformEl.setAttribute("explicit-source-supported", "true"); //NOI18N
data.appendChild(platformEl);
}
Element sourceRoots = doc.createElementNS(J2SEModularProject.PROJECT_CONFIGURATION_NAMESPACE,"source-roots"); //NOI18N
if (srcRoot != null) {
Element root = doc.createElementNS (J2SEModularProject.PROJECT_CONFIGURATION_NAMESPACE,"root"); //NOI18N
root.setAttribute ("id","src.dir"); //NOI18N
root.setAttribute ("pathref","src.dir.path"); //NOI18N
sourceRoots.appendChild(root);
ep.setProperty("src.dir", srcRoot); // NOI18N
ep.setProperty("src.dir.path", srcRootPath); // NOI18N
}
data.appendChild (sourceRoots);
Element testRoots = doc.createElementNS(J2SEModularProject.PROJECT_CONFIGURATION_NAMESPACE,"test-roots"); //NOI18N
if (srcRoot != null) {
Element root = doc.createElementNS (J2SEModularProject.PROJECT_CONFIGURATION_NAMESPACE,"root"); //NOI18N
root.setAttribute ("id","test.src.dir"); //NOI18N
root.setAttribute ("pathref","test.src.dir.path"); //NOI18N
testRoots.appendChild (root);
ep.setProperty("test.src.dir", srcRoot); // NOI18N
ep.setProperty("test.src.dir.path", testSrcRootPath); // NOI18N
}
data.appendChild (testRoots);
h.putPrimaryConfigurationData(data, true);
ep.setProperty(ProjectProperties.ANNOTATION_PROCESSING_ENABLED, "true"); // NOI18N
ep.setProperty(ProjectProperties.ANNOTATION_PROCESSING_ENABLED_IN_EDITOR, "false"); // NOI18N
ep.setProperty(ProjectProperties.ANNOTATION_PROCESSING_RUN_ALL_PROCESSORS, "true"); // NOI18N
ep.setProperty(ProjectProperties.ANNOTATION_PROCESSING_PROCESSORS_LIST, ""); // NOI18N
ep.setProperty(ProjectProperties.ANNOTATION_PROCESSING_SOURCE_OUTPUT, "${build.generated.sources.dir}/ap-source-output"); // NOI18N
ep.setProperty(ProjectProperties.ANNOTATION_PROCESSING_PROCESSOR_OPTIONS, ""); // NOI18N
ep.setProperty("dist.dir", "dist"); // NOI18N
ep.setComment("dist.dir", new String[] {"# " + NbBundle.getMessage(J2SEModularProjectGenerator.class, "COMMENT_dist.dir")}, false); // NOI18N
ep.setProperty("javac.classpath", ""); // NOI18N
ep.setProperty(ProjectProperties.JAVAC_PROCESSORPATH, new String[] {ref(ProjectProperties.JAVAC_CLASSPATH, true)}); // NOI18N
ep.setProperty("javac.test.processorpath", new String[] {ref(ProjectProperties.JAVAC_TEST_CLASSPATH,true)}); // NOI18N
ep.setProperty("build.sysclasspath", "ignore"); // NOI18N
ep.setComment("build.sysclasspath", new String[] {"# " + NbBundle.getMessage(J2SEModularProjectGenerator.class, "COMMENT_build.sysclasspath")}, false); // NOI18N
ep.setProperty("run.classpath", ""); // NOI18N
ep.setProperty("debug.classpath", new String[] { // NOI18N
ref(ProjectProperties.RUN_CLASSPATH,true)
});
ep.setComment("debug.classpath", new String[] { // NOI18N
"# " + NbBundle.getMessage(J2SEModularProjectGenerator.class, "COMMENT_debug.transport"),
"#debug.transport=dt_socket"
}, false);
ep.setProperty("jar.compress", "false"); // NOI18N
ep.setProperty("javac.compilerargs", ""); // NOI18N
ep.setComment("javac.compilerargs", new String[] {
"# " + NbBundle.getMessage(J2SEModularProjectGenerator.class, "COMMENT_javac.compilerargs"), // NOI18N
}, false);
ep.setProperty("javac.source", sourceLevel.toString()); // NOI18N
ep.setProperty("javac.target", sourceLevel.toString()); // NOI18N
ep.setProperty("javac.deprecation", "false"); // NOI18N
ep.setProperty("javac.test.classpath", new String[] { // NOI18N
ref(ProjectProperties.JAVAC_CLASSPATH, true)
});
ep.setProperty("run.test.classpath", new String[] { // NOI18N
ref(ProjectProperties.JAVAC_TEST_CLASSPATH, true)
});
ep.setProperty("debug.test.classpath", new String[] { // NOI18N
ref(ProjectProperties.RUN_TEST_CLASSPATH, true)
});
//Modules
ep.setProperty(ProjectProperties.JAVAC_MODULEPATH, ""); //NOI18N
ep.setProperty(ProjectProperties.JAVAC_PROCESSORMODULEPATH, ""); //NOI18N
ep.setProperty(ProjectProperties.RUN_MODULEPATH, new String[] {
ref(ProjectProperties.JAVAC_MODULEPATH, false),
ref(ProjectProperties.BUILD_MODULES_DIR, true)
});
ep.setProperty(ProjectProperties.DEBUG_MODULEPATH, new String[] {
ref(ProjectProperties.RUN_MODULEPATH, true)
});
ep.setProperty(ProjectProperties.JAVAC_TEST_MODULEPATH, new String[] {
ref(ProjectProperties.JAVAC_MODULEPATH, false),
ref(ProjectProperties.BUILD_MODULES_DIR, true)
});
ep.setProperty(ProjectProperties.RUN_TEST_MODULEPATH, new String[] {
ref(ProjectProperties.JAVAC_TEST_MODULEPATH, false),
ref(ProjectProperties.BUILD_TEST_MODULES_DIR, true)
});
ep.setProperty(ProjectProperties.DEBUG_TEST_MODULEPATH, new String[] {
ref(ProjectProperties.RUN_TEST_MODULEPATH, true)
});
ep.setProperty("build.generated.dir", "${build.dir}/generated"); // NOI18N
ep.setProperty("build.dir", "build"); // NOI18N
ep.setComment("build.dir", new String[] {"# " + NbBundle.getMessage(J2SEModularProjectGenerator.class, "COMMENT_build.dir")}, false); // NOI18N
ep.setProperty("build.classes.dir", "${build.dir}/classes"); // NOI18N //TODO: For What?
ep.setProperty(ProjectProperties.BUILD_MODULES_DIR, "${build.dir}/modules"); // NOI18N //TODO: For What?
ep.setProperty("build.generated.sources.dir", "${build.dir}/generated-sources"); // NOI18N
ep.setProperty("build.test.classes.dir", "${build.dir}/test/classes"); // NOI18N
ep.setProperty("build.test.modules.dir", "${build.dir}/test/modules"); // NOI18N
ep.setProperty("build.test.results.dir", "${build.dir}/test/results"); // NOI18N
ep.setProperty("build.classes.excludes", "**/*.java,**/*.form"); // NOI18N
ep.setProperty("dist.javadoc.dir", "${dist.dir}/javadoc"); // NOI18N
ep.setProperty("platform.active", platformId); // NOI18N
ep.setProperty(ProjectProperties.RUN_JVM_ARGS, ""); // NOI18N
ep.setComment(ProjectProperties.RUN_JVM_ARGS, new String[] {
"# " + NbBundle.getMessage(J2SEModularProjectGenerator.class, "COMMENT_run.jvmargs"), // NOI18N
"# " + NbBundle.getMessage(J2SEModularProjectGenerator.class, "COMMENT_run.jvmargs_2"), // NOI18N
"# " + NbBundle.getMessage(J2SEModularProjectGenerator.class, "COMMENT_run.jvmargs_3"), // NOI18N
}, false);
ep.setProperty(ProjectProperties.JAVADOC_PRIVATE, "false"); // NOI18N
ep.setProperty(ProjectProperties.JAVADOC_NO_TREE, "false"); // NOI18N
ep.setProperty(ProjectProperties.JAVADOC_USE, "true"); // NOI18N
ep.setProperty(ProjectProperties.JAVADOC_NO_NAVBAR, "false"); // NOI18N
ep.setProperty(ProjectProperties.JAVADOC_NO_INDEX, "false"); // NOI18N
ep.setProperty(ProjectProperties.JAVADOC_HTML5, "false"); // NOI18N
ep.setProperty(ProjectProperties.JAVADOC_SPLIT_INDEX, "true"); // NOI18N
ep.setProperty(ProjectProperties.JAVADOC_AUTHOR, "false"); // NOI18N
ep.setProperty(ProjectProperties.JAVADOC_VERSION, "false"); // NOI18N
ep.setProperty(ProjectProperties.JAVADOC_WINDOW_TITLE, ""); // NOI18N
ep.setProperty(ProjectProperties.JAVADOC_ENCODING, "${"+ProjectProperties.SOURCE_ENCODING+"}"); // NOI18N
ep.setProperty(ProjectProperties.JAVADOC_ADDITIONALPARAM, ""); // NOI18N
Charset enc = FileEncodingQuery.getDefaultEncoding();
ep.setProperty(ProjectProperties.SOURCE_ENCODING, enc.name());
ep.setProperty(ProjectProperties.DIST_ARCHIVE_EXCLUDES,""); //NOI18N
ep.setComment(ProjectProperties.DIST_ARCHIVE_EXCLUDES,
new String[] {
"# " + NbBundle.getMessage(J2SEModularProjectGenerator.class, "COMMENT_dist.archive.excludes") //NOI18N
},
false);
//JLink
ep.setProperty(ProjectProperties.DIST_JLINK_DIR, "${"+ProjectProperties.DIST_DIR+"}/jlink");
ep.setProperty(ProjectProperties.DIST_JLINK_OUTPUT, "${"+ProjectProperties.DIST_JLINK_DIR+"}/"+antName);
ep.setProperty(ProjectProperties.JLINK_ADDITIONALMODULES, "");
ep.setComment(ProjectProperties.JLINK_ADDITIONALMODULES,
new String[] {
"# " + NbBundle.getMessage(J2SEModularProjectGenerator.class, "COMMENT_jlink.additionalmodules") //NOI18N
},
false);
ep.setProperty(ProjectProperties.JLINK_ADDITIONALPARAM, "");
ep.setComment(ProjectProperties.JLINK_ADDITIONALPARAM,
new String[] {
"# " + NbBundle.getMessage(J2SEModularProjectGenerator.class, "COMMENT_jlink.additionalparam") //NOI18N
},
false);
ep.setProperty(ProjectProperties.JLINK_LAUNCHER, "true");
ep.setProperty(ProjectProperties.JLINK_LAUNCHER_NAME, antName);
h.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH, ep);
ep = h.getProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH);
ep.setProperty(ProjectProperties.COMPILE_ON_SAVE, "true"); // NOI18N
h.putProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH, ep);
logUsage(Action.OPEN);
return h;
}
private static SpecificationVersion getSourceLevel (final JavaPlatform platform) {
if (defaultSourceLevel != null) {
return defaultSourceLevel;
} else {
return platform.getSpecification().getVersion();
}
}
private static String ref(@NonNull final String propertyName, final boolean lastEntry) {
return String.format("${%s}%s", propertyName, lastEntry ? "" : ":"); //NOI18N
}
// http://wiki.netbeans.org/UsageLoggingSpecification
static void logUsage(@NonNull Action action) {
assert action != null;
Logger logger = Logger.getLogger(J2SEModularProjectGenerator.METRICS_LOGGER);
LogRecord logRecord = new LogRecord(Level.INFO, action.getGenericLogMessage());
logRecord.setLoggerName(logger.getName());
logRecord.setParameters(new Object[]{
J2SEModularProject.TYPE
});
logger.log(logRecord);
logger = Logger.getLogger(J2SEModularProjectGenerator.J2SE_MODULAR_METRICS_LOGGER);
logRecord = new LogRecord(Level.INFO, action.getSpecificLogMessage());
logRecord.setLoggerName(logger.getName());
logger.log(logRecord);
}
//------------ Used by unit tests -------------------
private static SpecificationVersion defaultSourceLevel;
/**
* Unit test only method. Sets the default source level for tests
* where the default platform is not available.
* @param version the default source level set to project when it is created
*
*/
public static void setDefaultSourceLevel (SpecificationVersion version) {
defaultSourceLevel = version;
}
}