blob: ca084f6225061111910eb8ceb5431b72af8e9e53 [file] [log] [blame]
package org.eclipse.scout.sdk.operation.project;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Deque;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.TreeMap;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.pde.internal.core.ICoreConstants;
import org.eclipse.scout.sdk.internal.ScoutSdk;
import org.eclipse.scout.sdk.jobs.OperationJob;
import org.eclipse.scout.sdk.operation.IOperation;
import org.eclipse.scout.sdk.operation.jdt.JavaElementFormatOperation;
import org.eclipse.scout.sdk.util.NamingUtility;
import org.eclipse.scout.sdk.util.ScoutUtility;
import org.eclipse.scout.sdk.util.jdt.JdtUtility;
import org.eclipse.scout.sdk.util.typecache.IWorkingCopyManager;
@SuppressWarnings("restriction")
public class ScoutProjectNewOperation extends AbstractScoutProjectNewOperation {
private static final String EXT_TAG_NAME = "operation";
private static final String EXT_NAME = "newProjectOperation";
private static final String EXT_ATTR_CLASS_NAME = "class";
private static final String EXT_ATTR_ID_NAME = "id";
private static final String EXT_ATTR_REF_NAME = "referenceId";
private static final String EXT_ATTR_REF_TYPE_NAME = "execAfterReference";
public static final String DOCUMENTATION_SVC_SUFFIX = "Documentation";
public ScoutProjectNewOperation() {
}
@Override
public void init() {
}
@Override
public boolean isRelevant() {
return true;
}
@Override
public String getOperationName() {
return "Creating new Scout project...";
}
@Override
public void run(IProgressMonitor monitor, IWorkingCopyManager workingCopyManager) throws CoreException, IllegalArgumentException {
// collect all registered operations
TreeMap<String, P_OperationElement> ops = new TreeMap<String, P_OperationElement>();
IExtensionRegistry reg = Platform.getExtensionRegistry();
IExtensionPoint xp = reg.getExtensionPoint(ScoutSdk.PLUGIN_ID, EXT_NAME);
IExtension[] extensions = xp.getExtensions();
for (IExtension extension : extensions) {
IConfigurationElement[] elements = extension.getConfigurationElements();
for (IConfigurationElement element : elements) {
if (EXT_TAG_NAME.equals(element.getName())) {
P_OperationElement op = new P_OperationElement(element);
ops.put(op.id, op);
}
}
}
// build graph based on the references and remember invalid nodes
ArrayList<P_OperationElement> invalidNodes = new ArrayList<P_OperationElement>();
ArrayList<P_OperationElement> validNodes = new ArrayList<P_OperationElement>(ops.size());
for (P_OperationElement op : ops.values()) {
if (op.referenceId == null) {
validNodes.add(op);
}
else {
P_OperationElement refElement = ops.get(op.referenceId);
if (refElement != null) {
if (op.execAfterReference) {
refElement.children.add(op);
op.parent = refElement;
}
else {
op.children.add(refElement);
refElement.parent = op;
}
validNodes.add(op);
}
else {
invalidNodes.add(op); // the reference of this item could not be found -> execute at the end
ScoutSdk.logWarning("New Project Operation reference '" + op.referenceId + "' defined by '" + op.op.getClass().getName() + "' could not be found.");
}
}
}
// find root nodes and check that at least one root exists
Collection<P_OperationElement> roots = getRootOperations(validNodes);
if (roots.size() == 0) {
throw new IllegalArgumentException("not operation root node could be found! Check the new project operation references.");
}
// traverse the tree collecting all items in a level-order-traversal into a flat list
// if several root nodes have been found (independent trees), the trees are executed in serial order (complete first tree, complete second tree, ...)
LinkedHashSet<P_OperationElement> collector = new LinkedHashSet<P_OperationElement>(ops.size());
for (P_OperationElement root : roots) {
breadthFirstTraverse(root, collector);
}
// add all invalid nodes to the end assuming that no one depends on them but they may depend on others (which are not present)
collector.addAll(invalidNodes);
// execute the operations
execOperations(monitor, workingCopyManager, collector.toArray(new P_OperationElement[collector.size()]));
// async post processing
OperationJob postProcessJob = new OperationJob(new P_PostProcessOperation(getCreatedBundlesList()));
postProcessJob.schedule(200);
}
private Collection<P_OperationElement> getRootOperations(Collection<P_OperationElement> nodes) {
ArrayList<P_OperationElement> roots = new ArrayList<P_OperationElement>();
for (P_OperationElement el : nodes) {
if (el.parent == null) {
roots.add(el);
}
}
return roots;
}
private void breadthFirstTraverse(P_OperationElement root, Collection<P_OperationElement> collector) {
Deque<P_OperationElement> deck = new ArrayDeque<P_OperationElement>();
deck.addLast(root);
while (!deck.isEmpty()) {
P_OperationElement el = deck.removeFirst();
for (P_OperationElement child : el.children) {
if (collector.contains(child)) {
throw new IllegalArgumentException("Cycle detected in new scout project operation tree.");
}
deck.addLast(child);
}
collector.add(el);
}
}
protected String computeExecutionEnvironment() {
return JdtUtility.getDefaultJvmExecutionEnvironment(getTargetPlatformVersion());
}
protected void putInitialProperties() {
String javaExecEnvId = computeExecutionEnvironment();
String maxPermSize = "";
double javaVersion = JdtUtility.getExecEnvVersion(javaExecEnvId);
if (javaVersion < 1.8) {
maxPermSize = "-XX:MaxPermSize=256m";
}
getProperties().setProperty(PROP_EXEC_ENV, javaExecEnvId);
getProperties().setProperty(PROP_JAVA_VERSION, "" + javaVersion);
getProperties().setProperty(PROP_MAX_PERM_SIZE, maxPermSize);
getProperties().setProperty(PROP_OS, ScoutSdk.getDefault().getBundle().getBundleContext().getProperty(ICoreConstants.OSGI_OS));
getProperties().setProperty(PROP_WS, ScoutSdk.getDefault().getBundle().getBundleContext().getProperty(ICoreConstants.OSGI_WS));
getProperties().setProperty(PROP_ARCH, ScoutSdk.getDefault().getBundle().getBundleContext().getProperty(ICoreConstants.OSGI_ARCH));
getProperties().setProperty(PROP_LOCALHOST, getHostName());
getProperties().setProperty(PROP_CURRENT_DATE, SimpleDateFormat.getDateInstance(SimpleDateFormat.DEFAULT).format(new Date()));
getProperties().setProperty(PROP_USER_NAME, ScoutUtility.getUsername());
String txtSvcName = NamingUtility.toJavaCamelCase(getProjectAlias(), false);
getProperties().setProperty(CreateSharedPluginOperation.PROP_TEXT_SERVICE_NAME, txtSvcName);
getProperties().setProperty(CreateSharedPluginOperation.PROP_DOC_TEXT_SERVICE_NAME, txtSvcName + DOCUMENTATION_SVC_SUFFIX);
}
private void execOperations(IProgressMonitor monitor, IWorkingCopyManager workingCopyManager, P_OperationElement[] ops) throws CoreException, IllegalArgumentException {
monitor.beginTask(getOperationName(), ops.length);
putInitialProperties();
for (P_OperationElement opElement : ops) {
// execute the pipeline as defined in IScoutProjectNewOperation
IScoutProjectNewOperation o = opElement.op;
o.setProperties(getProperties());
if (o.isRelevant()) {
o.init();
o.validate();
o.run(new SubProgressMonitor(monitor, 1), workingCopyManager);
}
monitor.worked(1);
}
ResourcesPlugin.getWorkspace().checkpoint(false);
monitor.done();
}
private static String getHostName() {
try {
return InetAddress.getLocalHost().getHostName().toLowerCase();
}
catch (Exception e) {
ScoutSdk.logInfo("Unable to retrieve localhost name.", e);
return null;
}
}
private static class P_PostProcessOperation implements IOperation {
private final List<IJavaProject> m_projectsToPostProcess;
private P_PostProcessOperation(List<IJavaProject> projectsToPostProcess) {
m_projectsToPostProcess = projectsToPostProcess;
}
@Override
public String getOperationName() {
return "Post Processing created projects...";
}
@Override
public void validate() throws IllegalArgumentException {
}
@Override
public void run(IProgressMonitor monitor, IWorkingCopyManager workingCopyManager) throws CoreException, IllegalArgumentException {
try {
JdtUtility.waitForIndexesReady();
if (m_projectsToPostProcess != null && m_projectsToPostProcess.size() > 0) {
// format all projects so that they match the workspace settings
for (IJavaProject jp : m_projectsToPostProcess) {
formatProject(monitor, workingCopyManager, jp);
}
}
}
catch (Exception e) {
ScoutSdk.logError("Cannot post process projects.", e);
}
}
private static void formatProject(IProgressMonitor monitor, IWorkingCopyManager workingCopyManager, IJavaProject p) throws CoreException {
for (IPackageFragment pck : p.getPackageFragments()) {
for (ICompilationUnit u : pck.getCompilationUnits()) {
if (!workingCopyManager.register(u, monitor)) {
// it is already registered. perform a reconcile.
workingCopyManager.reconcile(u, monitor);
}
JavaElementFormatOperation fo = new JavaElementFormatOperation(u, true);
fo.validate();
fo.run(monitor, workingCopyManager);
}
}
}
}
private static class P_OperationElement {
private final IScoutProjectNewOperation op;
private final String id;
private final String referenceId;
private final boolean execAfterReference;
private final ArrayList<P_OperationElement> children;
private P_OperationElement parent;
private P_OperationElement(IConfigurationElement element) throws CoreException {
op = (IScoutProjectNewOperation) element.createExecutableExtension(EXT_ATTR_CLASS_NAME);
id = cleanString(element.getAttribute(EXT_ATTR_ID_NAME));
referenceId = cleanString(element.getAttribute(EXT_ATTR_REF_NAME));
children = new ArrayList<P_OperationElement>();
String execAfter = cleanString(element.getAttribute(EXT_ATTR_REF_TYPE_NAME));
boolean after = true;
if (execAfter != null) {
if ("false".equalsIgnoreCase(execAfter)) {
after = false;
}
}
execAfterReference = after;
}
private static String cleanString(String input) {
if (input == null) return null;
input = input.trim();
if (input.length() == 0) return null;
return input;
}
}
}