/******************************************************************************* * Copyright (c) 2012, 2014 Pivotal Software, Inc. * 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: * Pivotal Software, Inc. - initial API and implementation *******************************************************************************/ package com.vmware.vfabric.ide.eclipse.tcserver.internal.core; import java.util.HashSet; import java.util.Set; import java.util.concurrent.TimeoutException; import org.apache.commons.lang.StringUtils; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jst.server.tomcat.core.internal.PublishOperation2; import org.eclipse.jst.server.tomcat.core.internal.TomcatServerBehaviour; import org.eclipse.jst.server.tomcat.core.internal.WebModule; import org.eclipse.jst.server.tomcat.core.internal.xml.server40.ServerInstance; import org.eclipse.osgi.util.NLS; import org.eclipse.wst.server.core.IModule; import org.eclipse.wst.server.core.IServer; import org.eclipse.wst.server.core.model.IModuleFile; import org.eclipse.wst.server.core.model.IModuleFolder; import org.eclipse.wst.server.core.model.IModuleResource; import org.eclipse.wst.server.core.model.IModuleResourceDelta; import org.eclipse.wst.server.core.model.PublishOperation; import org.eclipse.wst.server.core.model.ServerBehaviourDelegate; import org.eclipse.wst.server.core.util.PublishHelper; import org.eclipse.wst.sse.core.StructuredModelManager; import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; import org.eclipse.wst.xml.core.internal.contentmodel.util.NamespaceTable; import org.eclipse.wst.xml.core.internal.document.DOMModelImpl; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument; import org.springframework.util.AntPathMatcher; /** * Publishes and reloads modules through JMX. Only modules that have auto reload * set to false in the tc Server configuration are reloaded. If a server does * not have a local configuration the module is always re-deployed using a war * file. * @author Steffen Pingel * @author Christian Dupuis * @author Leo Dos Santos */ public class TcPublisher extends PublishOperation2 { public static final String DEFAULT_NAMESPACE_URI = "http://www.springframework.org/schema/beans"; private final IModule module2; public TcPublisher(TomcatServerBehaviour server, int kind, IModule[] module, int deltaKind) { super(server, kind, module, deltaKind); module2 = module[0]; } /** * @see PublishOperation#execute(IProgressMonitor, IAdaptable) */ @Override public void execute(IProgressMonitor monitor, IAdaptable info) throws CoreException { if (!((TcServer) server.getTomcatServer()).isEnhancedRedeployEnabled() || isModuleAutoReloadEnabled()) { // server will reload applications return; } // determine if module needs to be reloaded DeployInfo deployer = new DeployInfo(server, module); if (deltaKind == ServerBehaviourDelegate.REMOVED || server.getTomcatServer().isServeModulesWithoutPublish()) { if (!deployer.isLocal()) { TcUndeployModuleCommand command = new TcUndeployModuleCommand(deployer.getTcServerBehaviour(), deployer.getService(), deployer.getHost(), deployer.getContextPath()); try { command.execute(); } catch (TimeoutException e) { throw new CoreException(new Status(IStatus.ERROR, ITcServerConstants.PLUGIN_ID, NLS.bind( "Timeout while publishing module ''{0}''", module2.getName()))); } catch (CoreException e) { throw new CoreException(new Status(IStatus.ERROR, ITcServerConstants.PLUGIN_ID, NLS.bind( "Failed to undeploy module ''{0}''", module2.getName()))); } } // no reload necessary return; } if (kind == IServer.PUBLISH_CLEAN || kind == IServer.PUBLISH_FULL) { // force reload reload(deployer, monitor); return; } if (!deployer.isLocal()) { // force redeploy since files can not be copied locally reload(deployer, monitor); return; } Set<IModuleFile> files = new HashSet<IModuleFile>(); IModuleResourceDelta[] delta = ((TcServerBehaviour) server).getPublishedResourceDelta(module); int size = delta.length; for (int i = 0; i < size; i++) { if (!onlyStaticResources(delta[i], files)) { // a dynamic resource has changed, reload app reload(deployer, monitor); return; } } } /** * Checks if the given <code>file</code> is a root node that is a known * Spring namespace. */ private boolean checkIfSpringConfigurationFile(IFile file) { IStructuredModel model = null; try { model = StructuredModelManager.getModelManager().getExistingModelForRead(file); if (model == null) { model = StructuredModelManager.getModelManager().getModelForRead(file); } if (model != null) { IDOMDocument document = ((DOMModelImpl) model).getDocument(); if (document != null && document.getDocumentElement() != null) { String namespaceUri = document.getDocumentElement().getNamespaceURI(); NamespaceTable table = new NamespaceTable(document); if (DEFAULT_NAMESPACE_URI.equals(namespaceUri) || table.getNamespaceInfoForURI(DEFAULT_NAMESPACE_URI) != null) { return false; } } } } catch (Exception e) { } finally { if (model != null) { model.releaseFromRead(); } model = null; } return true; } private boolean isModuleAutoReloadEnabled() { TcServer tcServer = (TcServer) server.getServer().loadAdapter(TcServer.class, null); IModule module2 = module[0]; try { ServerInstance serverInstance = tcServer.getTomcatConfiguration().getServerInstance(); if (serverInstance != null) { WebModule webModule = tcServer.getTomcatConfiguration().getWebModule(module2); return webModule != null && webModule.isReloadable(); } } catch (CoreException e) { // ignore } return false; } /** * Check if resource delta only contains static resources */ private boolean onlyStaticResources(IModuleResourceDelta delta, Set<IModuleFile> files) { if (delta.getModuleResource() instanceof IModuleFolder) { for (IModuleResourceDelta child : delta.getAffectedChildren()) { if (!onlyStaticResources(child, files)) { return false; } } return true; } else { if (delta.getModuleResource() instanceof IModuleFile) { files.add((IModuleFile) delta.getModuleResource()); } String name = delta.getModuleResource().getName(); // make that configurable if (name.endsWith(".xml")) { IFile file = (IFile) delta.getModuleResource().getAdapter(IFile.class); // check for spring context xml files first but exclude if (!checkIfSpringConfigurationFile(file)) { return false; } } boolean isStatic = false; // Check the configuration options for static resources AntPathMatcher matcher = new AntPathMatcher(); TcServer tcServer = (TcServer) server.getServer().loadAdapter(TcServer.class, null); for (String pattern : StringUtils.splitByWholeSeparator(tcServer.getStaticFilenamePatterns(), ",")) { if (pattern.startsWith("!") && matcher.match(pattern.substring(1), name)) { isStatic = false; } else if (matcher.match(pattern, name)) { isStatic = true; } } return isStatic; } } private void reload(DeployInfo deployer, IProgressMonitor monitor) throws CoreException { if (server.getServer().getServerState() != IServer.STATE_STARTED) { return; } try { String deployPath; if (deployer.isLocal()) { deployPath = null; } else { // server has no local configuration, re-deploy application // deploy application to war file for upload IPath path = deployer.getTcServerBehaviour().getServerDeployDirectory() .append(deployer.getContextPath() + ".war"); IPath base = server.getRuntimeBaseDirectory(); PublishHelper helper = new PublishHelper(base.append("temp").toFile()); IModuleResource[] mr = ((TcServerBehaviour) server).getResources(module); IStatus[] stat = helper.publishZip(mr, path, monitor); if (stat.length > 0) { throw new CoreException(new MultiStatus(ITcServerConstants.PLUGIN_ID, 0, stat, NLS.bind( "Failed to gather resources to publish module ''{0}''", module2.getName()), null)); } deployPath = deployer.getTcServerBehaviour().getDeployRoot() + path.lastSegment(); } TcReloadModuleCommand command = new TcReloadModuleCommand(deployer.getTcServerBehaviour(), deployer.getService(), deployer.getHost(), deployer.getContextPath(), deployPath); command.setForceDeploy(deployPath != null); command.execute(); } catch (TimeoutException e) { throw new CoreException(new Status(IStatus.ERROR, ITcServerConstants.PLUGIN_ID, NLS.bind( "Timeout while publishing module ''{0}''", module2.getName()))); } catch (CoreException e) { throw new CoreException(new Status(IStatus.ERROR, ITcServerConstants.PLUGIN_ID, NLS.bind( "Failed to publish module ''{0}''", module2.getName()))); } } }