/*******************************************************************************
* Copyright (c) 2009, 2010 SpringSource, a divison of VMware, 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:
* SpringSource, a division of VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.virgo.ide.runtime.internal.core;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IProject;
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.NullProgressMonitor;
import org.eclipse.jst.server.core.PublishUtil;
import org.eclipse.virgo.bundlor.util.AntPathMatcher;
import org.eclipse.virgo.ide.facet.core.FacetCorePlugin;
import org.eclipse.virgo.ide.facet.core.FacetUtils;
import org.eclipse.virgo.ide.manifest.core.BundleManifestCorePlugin;
import org.eclipse.virgo.ide.module.core.ServerModuleDelegate;
import org.eclipse.virgo.ide.runtime.core.ServerUtils;
import org.eclipse.virgo.util.common.StringUtils;
import org.eclipse.virgo.util.osgi.manifest.BundleManifest;
import org.eclipse.virgo.util.osgi.manifest.BundleManifestFactory;
import org.eclipse.wst.server.core.IModule;
import org.eclipse.wst.server.core.IServer;
import org.eclipse.wst.server.core.ServerUtil;
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;
/**
* {@link PublishOperation} extension that deals with deploy, clean and refresh of dm Server modules.
* @author Christian Dupuis
* @since 1.0.0
*/
@SuppressWarnings("restriction")
public class ServerPublishOperation extends PublishOperation {
private int deltaKind;
private int kind;
private IModule[] modules;
private ServerBehaviour server;
public ServerPublishOperation(ServerBehaviour server, int kind, IModule[] module, int deltaKind) {
super("Publish to server", "Publish module to SpringSource dm Server");
this.server = server;
this.kind = kind;
this.modules = module;
this.deltaKind = deltaKind;
}
@Override
public void execute(IProgressMonitor monitor, IAdaptable info) throws CoreException {
boolean shouldRedeploy = false;
List<IStatus> status = new ArrayList<IStatus>();
if (modules.length == 1) {
shouldRedeploy = publishModule(modules[0], status, monitor);
}
boolean shouldReployChild = false;
IProject project = modules[0].getProject();
if (!FacetUtils.isBundleProject(project) && !FacetUtils.isParProject(project)
&& ServerUtils.getServer(server).getChildModules(modules) != null && !FacetUtils.isPlanProject(project)) {
for (IModule module : ServerUtils.getServer(server).getChildModules(modules)) {
if (publishJar(module, status, monitor)) {
shouldReployChild = true;
}
}
}
if (shouldRedeploy || shouldReployChild) {
server.getServerDeployer().redeploy(modules[0]);
}
server.onModulePublishStateChange(modules, IServer.PUBLISH_STATE_NONE);
}
@Override
public int getKind() {
return REQUIRED;
}
@Override
public int getOrder() {
return 0;
}
/**
* 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();
// if (NamespaceUtils.DEFAULT_NAMESPACE_URI.equals(namespaceUri)
// || new DelegatingNamespaceHandlerResolver(JdtUtils.getClassLoader(file.getProject(), null),
// null).resolve(namespaceUri) != null) {
// return false;
// }
// }
// }
// }
// catch (Exception e) {
// }
// finally {
// if (model != null) {
// model.releaseFromRead();
// }
// model = null;
// }
// return true;
// }
/**
* 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();
boolean isStatic = false;
// Check the configuration options for static resources
AntPathMatcher matcher = new AntPathMatcher();
for (String pattern : StringUtils.delimitedListToStringArray(ServerUtils.getServer(server)
.getStaticFilenamePatterns(), ",")) {
if (pattern.startsWith("!") && matcher.match(pattern.substring(1), name)) {
isStatic = false;
}
else if (matcher.match(pattern, name)) {
isStatic = true;
}
}
return isStatic;
}
}
private boolean publishJar(IModule module, List<IStatus> status, IProgressMonitor monitor) throws CoreException {
IPath path = server.getModuleDeployDirectory(modules[0]).append("WEB-INF").append("lib");
IPath zipPath = path.append(module.getName() + ".jar");
if (kind == IServer.PUBLISH_CLEAN || deltaKind == ServerBehaviourDelegate.REMOVED) {
if (zipPath.toFile().exists()) {
zipPath.toFile().delete();
}
if (deltaKind == ServerBehaviourDelegate.REMOVED) {
return false;
}
}
if (kind != IServer.PUBLISH_CLEAN && kind != IServer.PUBLISH_FULL) {
IModuleResourceDelta[] delta = server.getPublishedResourceDelta(new IModule[] { modules[0], module });
if (delta == null || delta.length == 0) {
return false;
}
}
if (!path.toFile().exists()) {
path.toFile().mkdirs();
}
PublishUtil.publishZip(server.getResources(new IModule[] { modules[0], module }), zipPath, monitor);
return true;
}
/**
* Creates a dummy manifest for WTP Dynamic Web Projects only
*/
private void publishManifest(IModule module, IPath path) {
if (FacetUtils.hasProjectFacet(module.getProject(), FacetCorePlugin.WEB_FACET_ID)) {
File manifestFile = path.append(BundleManifestCorePlugin.MANIFEST_FOLDER_NAME).append(
BundleManifestCorePlugin.MANIFEST_FILE_NAME).toFile();
if (manifestFile.exists()) {
return;
}
BundleManifest manifest = BundleManifestFactory.createBundleManifest();
Writer writer = null;
try {
manifestFile.getParentFile().mkdirs();
writer = new FileWriter(manifestFile);
manifest.write(writer);
}
catch (IOException e) {
}
finally {
if (writer != null) {
try {
writer.flush();
writer.close();
}
catch (IOException e) {
}
}
}
}
}
private boolean publishModule(IModule module, List<IStatus> status, IProgressMonitor monitor) throws CoreException {
IPath path = server.getModuleDeployDirectory(module);
if (deltaKind == ServerBehaviourDelegate.REMOVED) {
File f = path.toFile();
if (ServerUtils.getServer(server).getServer().getServerState() == IServer.STATE_STARTED) {
server.getServerDeployer().undeploy(module);
}
if (f.exists() && !path.equals(server.getServerDeployDirectory())) {
PublishUtil.deleteDirectory(f, new NullProgressMonitor());
}
if (module.getModuleType().getId().equals(FacetCorePlugin.PLAN_FACET_ID)) {
// Delete the plan file
path = path.append(module.getId().substring(module.getId().lastIndexOf('/')));
File planFile = path.toFile();
if (planFile.exists()) {
planFile.delete();
}
// Delete all child modules that are not being used anymore
ServerModuleDelegate planModule = (ServerModuleDelegate) module.loadAdapter(ServerModuleDelegate.class,
null);
IServer s = server.getServer();
for (IModule childModule : planModule.getChildModules()) {
if (!ServerUtil.containsModule(s, childModule, monitor)) {
IPath modulePath = server.getModuleDeployDirectory(childModule);
File moduleFile = modulePath.toFile();
if (moduleFile.exists()) {
PublishUtil.deleteDirectory(moduleFile, new NullProgressMonitor());
}
}
}
}
return false;
}
if (kind == IServer.PUBLISH_CLEAN || kind == IServer.PUBLISH_FULL) {
IModuleResource[] mr = server.getResources(modules);
status.addAll(Arrays.asList(PublishUtil.publishFull(mr, path, monitor)));
// Hack to get a MANIFEST.MF into the deployment area
publishManifest(module, path);
if (ServerUtils.getServer(server).getServer().getServerState() == IServer.STATE_STARTED) {
// redeploy
return true;
}
return false;
}
IModuleResourceDelta[] delta = server.getPublishedResourceDelta(modules);
for (IModuleResourceDelta d : delta) {
status.addAll(Arrays.asList(PublishUtil.publishDelta(d, path, monitor)));
}
publishManifest(module, path);
if (ServerUtils.getServer(server).getServer().getServerState() == IServer.STATE_STARTED
&& deltaKind != ServerBehaviourDelegate.NO_CHANGE) {
Set<IModuleFile> files = new HashSet<IModuleFile>();
// first check if only static resources are changed
boolean onlyStaticResources = true;
for (IModuleResourceDelta d : delta) {
if (!onlyStaticResources(d, files)) {
onlyStaticResources = false;
// don't break to get a full set of all files
}
}
if (!onlyStaticResources) {
// redeploy
return true;
}
else {
// refresh static resources
for (IModuleFile file : files) {
server.getServerDeployer().refreshStatic(module, file);
}
}
}
return false;
}
}