blob: a92a22cd871eac3a31702bdb5c2f2ef05e0503b1 [file] [log] [blame]
/***************************************************************************************************
* Copyright (c) 2005, 2009 Eteration A.S. and Gorkem Ercan. All rights reserved. This program and the
* accompanying materials are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors: Gorkem Ercan - initial API and implementation
*
**************************************************************************************************/
package org.eclipse.jst.server.generic.core.internal.publishers;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.eclipse.ant.ui.launching.IAntLaunchConfigurationConstants;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jst.server.core.IEnterpriseApplication;
import org.eclipse.jst.server.core.IWebModule;
import org.eclipse.jst.server.generic.core.internal.CorePlugin;
import org.eclipse.jst.server.generic.core.internal.GenericPublisher;
import org.eclipse.jst.server.generic.core.internal.GenericServer;
import org.eclipse.jst.server.generic.core.internal.GenericServerBehaviour;
import org.eclipse.jst.server.generic.core.internal.GenericServerCoreMessages;
import org.eclipse.jst.server.generic.core.internal.Trace;
import org.eclipse.jst.server.generic.internal.core.util.FileUtil;
import org.eclipse.jst.server.generic.servertype.definition.Module;
import org.eclipse.jst.server.generic.servertype.definition.PublisherData;
import org.eclipse.wst.server.core.IModule;
import org.eclipse.wst.server.core.IModuleArtifact;
import org.eclipse.wst.server.core.IServer;
import org.eclipse.wst.server.core.model.ServerBehaviourDelegate;
import org.osgi.framework.Bundle;
/**
* Ant based publisher. All the properties defined in the server definition file
* are passed into the ANT build file as properties. In addition to the
* properties defined in the server definition <I>module.dir</I>,
* <I>module.name,</I> and <I>server.publish.dir</I> are computed and passed
* to the definition file.
* <ul>
* <li>module.dir: includes the root of the module project file</li>
* <li>module.name: the name of the module</li>
* <li>server.publish.dir: the directory to put the deployment units</li>
* <li>project.working.dir: the working dir of the project that deployed module
* is in</li>
* </ul>
*
* @author Gorkem Ercan
*/
public class AntPublisher extends GenericPublisher {
/**
* Copy of IExternalToolConstants.ATTR_LOCATION
*/
private static final String ATTR_LOCATION = "org.eclipse.ui.externaltools.ATTR_LOCATION"; //$NON-NLS-1$
/**
* Copy of the IAntUIConstants.REMOTE_ANT_PROCESS_FACTORY_ID
*/
private static final String REMOTE_ANT_PROCESS_FACTORY_ID= "org.eclipse.ant.ui.remoteAntProcessFactory"; //$NON-NLS-1$
private static final String JAR_PROTOCOL_PREFIX = "jar"; //$NON-NLS-1$
/**
* publisher id for ANT publisher.
*/
public static final String PUBLISHER_ID = "org.eclipse.jst.server.generic.antpublisher"; //$NON-NLS-1$
protected static final String PROP_SERVER_PUBLISH_DIR = "server.publish.dir";//$NON-NLS-1$
protected static final String PROP_PROJECT_WORKING_DIR = "project.working.dir";//$NON-NLS-1$
protected static final String PROP_MODULE_DIR = "module.dir";//$NON-NLS-1$
protected static final String PROP_MODULE_NAME = "module.name";//$NON-NLS-1$
protected static final String PROP_CONTEXT_ROOT = "contextRoot";//$NON-NLS-1$
protected static final String PROP_PROJECT_NAME = "project.name";//$NON-NLS-1$
protected static final String PROP_PROJECT_LOCATION = "project.location"; //$NON-NLS-1$
protected static final String MODULE_PUBLISH_TARGET_PREFIX = "target.publish."; //$NON-NLS-1$
protected static final String MODULE_UNPUBLISH_TARGET_PREFIX = "target.unpublish.";//$NON-NLS-1$
protected static final String DATA_NAME_BUILD_FILE = "build.file";//$NON-NLS-1$
protected static final String PROP_MODULE_ARCHIVE_NAME = "module.archive.name"; //$NON-NLS-1$
/*
* (non-Javadoc)
*
* @see org.eclipse.wtp.server.core.model.IPublisher#publish(org.eclipse.wtp.server.core.resources.IModuleResource[],
* org.eclipse.core.runtime.IProgressMonitor)
*/
public IStatus[] publish(IModuleArtifact[] resource, IProgressMonitor monitor) {
if (getModule().length > 1 || // only respond to root module calls.
!publishNeeded() ||
monitor.isCanceled()) return null;
try {
assembleModule(monitor);
File file = getCustomBuildFile();
if ( file == null){// no user selected build file use the adapter default.
file = computeBuildFile();
}
runAnt(file.toString(), getPublishTargetsForModule(), getPublishProperties(), monitor);
} catch (CoreException e) {
IStatus s = new Status(IStatus.ERROR, CorePlugin.PLUGIN_ID, 0, GenericServerCoreMessages.errorPublishAntpublisher, e);
CorePlugin.getDefault().getLog().log(s);
return new IStatus[] { s };
}
return null;
}
/**
* Checks if the Ant publisher actually needs to publish.
* For ear modules it also checks if any of the children modules requires publishing.
* @return true if ant publisher needs to publish.
*/
private boolean publishNeeded() {
if ( getKind() != IServer.PUBLISH_INCREMENTAL && getKind() != IServer.PUBLISH_AUTO )
return true;
if (getDeltaKind() != ServerBehaviourDelegate.NO_CHANGE )
return true;
if ( isModuleType(getModule()[0], "jst.ear") ){ //$NON-NLS-1$
IEnterpriseApplication earModule = (IEnterpriseApplication)getModule()[0].loadAdapter(IEnterpriseApplication.class, new NullProgressMonitor());
IModule[] childModules = earModule.getModules();
for (int i = 0; i < childModules.length; i++) {
IModule module = childModules[i];
IModule[] modules ={getModule()[0], module};
if (IServer.PUBLISH_STATE_NONE != this.getServer().getServer().getModulePublishState(modules))
return true;
}
}
return false;
}
protected void assembleModule(IProgressMonitor monitor) throws CoreException {
long time = System.currentTimeMillis();
AbstractModuleAssembler assembler = AbstractModuleAssembler.Factory.getModuleAssembler(getModule()[0], getServer());
assembler.assemble(monitor);
Trace.trace(Trace.PERFORMANCE, "AntPublisher.assembleModule(): <" + (System.currentTimeMillis()-time) + "ms> module: "+getModule()[0] ); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Returns the custom build file that user selected. Or returns null;
* @return
* @throws CoreException
*/
private File getCustomBuildFile() throws CoreException {
String filename = (String)getServer().getServerInstanceProperties().get( GenericServer.PROP_CUSTOM_BUILD_SCRIPT );
if( filename != null && filename.length()>0 ){
filename = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution( filename );
File file = new File(filename);
if ( !file.exists() ){
throw new CoreException(new Status(IStatus.ERROR,CorePlugin.PLUGIN_ID,
"Selected build file does not exist.")); //$NON-NLS-1$
}
return file;
}
return null;
}
/**
*
* @return file
* @throws CoreException
*/
private File computeBuildFile() throws CoreException {
Bundle bundle = Platform.getBundle(getServerRuntime().getServerTypeDefinition().getConfigurationElementNamespace());
URL bundleUrl = bundle.getEntry(getBuildFile());
URL fileURL = FileUtil.resolveURL(bundleUrl);
if (fileURL.getProtocol().equals(JAR_PROTOCOL_PREFIX)) {
OutputStream os = null;
InputStream is = null;
try {
String filename = fileURL.getPath();
String jarname = fileURL.getFile().substring(0, filename.indexOf('!'));
File jarFile = new File(new URL(jarname).getFile());
JarFile jar = new JarFile(jarFile);
File tmpFile = FileUtil.createTempFile(getBuildFile(), CorePlugin.getDefault().getStateLocation().toOSString());
os = new FileOutputStream(tmpFile);
String entryname = getBuildFile();
if (entryname.startsWith("/"))//$NON-NLS-1$
entryname = entryname.substring(1);
JarEntry entry = jar.getJarEntry(entryname);
is = jar.getInputStream(entry);
FileUtil.copy(is, os);
return tmpFile;
} catch (IOException e) {
IStatus s = new Status(IStatus.ERROR, CorePlugin.PLUGIN_ID, 0, "error creating temporary build file", e);//$NON-NLS-1$
CorePlugin.getDefault().getLog().log(s);
throw new CoreException(s);
} finally {
try {
if (is != null)
is.close();
if (os != null)
os.close();
} catch (IOException e) {
// ignore
}
}
}
return FileUtil.resolveFile(fileURL);
}
private String getPublishTargetsForModule() {
return doGetTargets(MODULE_PUBLISH_TARGET_PREFIX + getModuleTypeId());
}
private String getUnpublishTargetsForModule() {
return doGetTargets(MODULE_UNPUBLISH_TARGET_PREFIX + getModuleTypeId());
}
private String doGetTargets(String dataname) {
StringBuffer buffer = new StringBuffer();
Iterator iterator = getServerRuntime().getServerTypeDefinition().getPublisher(PUBLISHER_ID).getPublisherdata().iterator();
while (iterator.hasNext()) {
PublisherData data = (PublisherData) iterator.next();
if (dataname.equals(data.getDataname())) {
if (buffer.length() > 0)
buffer.append(",");//$NON-NLS-1$
buffer.append(data.getDatavalue());
}
}
return buffer.toString();
}
private String getModuleTypeId() {
return getModule()[0].getModuleType().getId();
}
private String getBuildFile() {
Iterator iterator = getServerRuntime().getServerTypeDefinition().getPublisher(PUBLISHER_ID).getPublisherdata().iterator();
while (iterator.hasNext()) {
PublisherData data = (PublisherData) iterator.next();
if (DATA_NAME_BUILD_FILE.equals(data.getDataname()))
return getServerRuntime().getServerTypeDefinition().getResolver().resolveProperties(data.getDatavalue());
}
return null;
}
private Map getPublishProperties() {
Map props = new HashMap();
// pass all properties to build file.
Map serverProperties = getServer().getServerInstanceProperties();
Map properties = getServerRuntime().getServerInstanceProperties();
properties.putAll(serverProperties);
Iterator propertyIterator = properties.keySet().iterator();
while (propertyIterator.hasNext()) {
String property = (String) propertyIterator.next();
String value = (String) properties.get(property);
if (value != null && value.trim().length() > 0)
props.put(property, properties.get(property));
}
Module module = getServerRuntime().getServerTypeDefinition().getModule(getModuleTypeId());
String modDir = module.getPublishDir();
modDir = getServerRuntime().getServerTypeDefinition().getResolver().resolveProperties(modDir);
IModule webModule = getModule()[0];
String moduleName = guessModuleName(webModule);
String contextRoot = guessContextRoot(webModule);
props.put(PROP_PROJECT_WORKING_DIR, getProjectWorkingLocation().toString());
props.put(PROP_MODULE_NAME, moduleName);
props.put(PROP_CONTEXT_ROOT, contextRoot);
if (isModuleType(webModule, "jst.ear")) {//$NON-NLS-1$
props.put(PROP_MODULE_ARCHIVE_NAME, moduleName + ".ear"); //$NON-NLS-1$
} else if (isModuleType(webModule, "jst.web")) { //$NON-NLS-1$
props.put(PROP_MODULE_ARCHIVE_NAME, moduleName + ".war"); //$NON-NLS-1$
} else if (isModuleType(webModule, "jst.ejb")) { //$NON-NLS-1$
props.put(PROP_MODULE_ARCHIVE_NAME, moduleName + ".jar"); //$NON-NLS-1$
}
if (webModule.getProject() != null) {
props.put(PROP_MODULE_DIR, getModuleWorkingDir().toString());
props.put(PROP_PROJECT_NAME, webModule.getProject().getName());
props.put(PROP_PROJECT_LOCATION, webModule.getProject().getLocation().toString());
}
props.put(PROP_SERVER_PUBLISH_DIR, modDir);
return props;
}
private IPath getModuleWorkingDir() {
return getProjectWorkingLocation().append(getModule()[0].getProject().getName());
}
private IPath getProjectWorkingLocation() {
GenericServerBehaviour genericServer = (GenericServerBehaviour) getServer().getServer().loadAdapter(ServerBehaviourDelegate.class, new NullProgressMonitor());
return genericServer.getTempDirectory();
}
private String guessModuleName(IModule module) {
String moduleName = module.getName();
if ("jst.web".equals(getModuleTypeId())) { //$NON-NLS-1$
IWebModule webModule = (IWebModule) getModule()[0].loadAdapter(IWebModule.class, null);
if (webModule == null) {
return module.getName();
}
String contextRoot = webModule.getURI(module);
moduleName = contextRoot.substring(0, contextRoot.lastIndexOf('.'));
}
return moduleName;
}
private String guessContextRoot(IModule module) {
String moduleName = guessModuleName(module);
String contextRoot = moduleName;
if ("jst.web".equals(getModuleTypeId())) { //$NON-NLS-1$
IWebModule webModule = (IWebModule) getModule()[0].loadAdapter(IWebModule.class, null);
if (webModule != null) {
contextRoot = webModule.getContextRoot();
if (contextRoot == null || contextRoot.length() == 0) {
contextRoot = moduleName;
}
}
}
return contextRoot;
}
private void runAnt(String buildFile, String targets, Map properties, IProgressMonitor monitor) throws CoreException {
long time = System.currentTimeMillis();
ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
ILaunchConfigurationType type = launchManager
.getLaunchConfigurationType(IAntLaunchConfigurationConstants.ID_ANT_LAUNCH_CONFIGURATION_TYPE);
if (type == null) {
IStatus s = new Status(IStatus.ERROR, CorePlugin.PLUGIN_ID, 0, GenericServerCoreMessages.antLauncherMissing, null);
throw new CoreException(s);
}
ILaunchConfigurationWorkingCopy wc = type.newInstance(null, properties.get(PROP_MODULE_NAME) + " module publisher"); //$NON-NLS-1$
wc.setContainer(null);
wc.setAttribute(ATTR_LOCATION, buildFile);
wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_CLASSPATH_PROVIDER, "org.eclipse.ant.ui.AntClasspathProvider"); //$NON-NLS-1$
wc.setAttribute(IAntLaunchConfigurationConstants.ATTR_ANT_TARGETS, targets);
wc.setAttribute(IAntLaunchConfigurationConstants.ATTR_ANT_PROPERTIES, properties);
wc.setAttribute(IDebugUIConstants.ATTR_LAUNCH_IN_BACKGROUND, false);
wc.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, true);
wc.setAttribute(IDebugUIConstants.ATTR_PRIVATE, true);
wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_SOURCE_PATH_PROVIDER, "org.eclipse.ant.ui.AntClasspathProvider"); //$NON-NLS-1$
IVMInstall vmInstall = getServerRuntime().getVMInstall();
if(vmInstall == null )//fallback to default VM if null.
vmInstall = JavaRuntime.getDefaultVMInstall();
wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_JRE_CONTAINER_PATH, JavaRuntime.newJREContainerPath(vmInstall).toPortableString());
wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME,
"org.eclipse.ant.internal.ui.antsupport.InternalAntRunner"); //$NON-NLS-1$
wc.setAttribute(DebugPlugin.ATTR_PROCESS_FACTORY_ID, REMOTE_ANT_PROCESS_FACTORY_ID);
setupAntLaunchConfiguration(wc);
if ( !monitor.isCanceled() )
{
ILaunchConfiguration launchConfig = wc.doSave();
launchConfig.launch(ILaunchManager.RUN_MODE, monitor, false, true);
Trace.trace(Trace.PERFORMANCE, "AntPublisher.runAnt():<" + (System.currentTimeMillis()-time) + "ms> module: "+getModule()[0] ); //$NON-NLS-1$ //$NON-NLS-2$
}
}
/**
* Hook method for subclasses.
*
* @param wc
*/
protected void setupAntLaunchConfiguration(ILaunchConfigurationWorkingCopy wc) {
// nothing to do
}
private static boolean isModuleType(IModule module, String moduleTypeId) {
if (module.getModuleType() != null && moduleTypeId.equals(module.getModuleType().getId()))
return true;
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jst.server.generic.internal.core.GenericPublisher#unpublish(org.eclipse.wst.server.core.IModule,
* org.eclipse.core.runtime.IProgressMonitor)
*/
public IStatus[] unpublish(IProgressMonitor monitor) {
if (getModule().length > 1)// only respond to root module calls.
return null;
try {
File file = computeBuildFile();
runAnt(file.toString(), getUnpublishTargetsForModule(), getPublishProperties(), monitor);
} catch (CoreException e) {
IStatus s = new Status(IStatus.ERROR, CorePlugin.PLUGIN_ID, 0, GenericServerCoreMessages.errorRemoveModuleAntpublisher, e);
return new IStatus[] { s };
}
return null;
}
}