| /*************************************************************************************************** |
| * 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; |
| } |
| } |