blob: 435d2d8596cddb517c5722a924f7b9dbbe2ef9ff [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.j2ee.earproject;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.api.java.project.JavaProjectConstants;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.api.project.Sources;
import org.netbeans.modules.j2ee.api.ejbjar.Car;
import org.netbeans.modules.j2ee.api.ejbjar.EjbJar;
import org.netbeans.modules.java.api.common.classpath.ClassPathSupport;
import org.netbeans.modules.j2ee.dd.api.application.Application;
import org.netbeans.modules.j2ee.dd.api.application.ApplicationMetadata;
import org.netbeans.modules.j2ee.dd.api.application.DDProvider;
import org.netbeans.modules.j2ee.deployment.common.api.EjbChangeDescriptor;
import org.netbeans.modules.j2ee.deployment.devmodules.api.Deployment;
import org.netbeans.modules.j2ee.deployment.devmodules.api.J2eeModule;
import org.netbeans.modules.j2ee.deployment.devmodules.api.J2eeApplication;
import org.netbeans.modules.j2ee.deployment.devmodules.api.ModuleChangeReporter;
import org.netbeans.modules.j2ee.deployment.devmodules.api.ModuleListener;
import org.netbeans.api.j2ee.core.Profile;
import org.netbeans.modules.j2ee.common.dd.DDHelper;
import org.netbeans.modules.j2ee.deployment.devmodules.api.ResourceChangeReporter;
import org.netbeans.modules.j2ee.deployment.devmodules.spi.ArtifactListener;
import org.netbeans.modules.j2ee.deployment.devmodules.spi.ArtifactListener.Artifact;
import org.netbeans.modules.j2ee.deployment.devmodules.spi.J2eeApplicationImplementation2;
import org.netbeans.modules.j2ee.deployment.devmodules.spi.J2eeApplicationProvider;
import org.netbeans.modules.j2ee.deployment.devmodules.spi.J2eeModuleFactory;
import org.netbeans.modules.j2ee.deployment.devmodules.spi.J2eeModuleProvider;
import org.netbeans.modules.j2ee.deployment.devmodules.spi.J2eeModuleProvider.DeployOnSaveSupport;
import org.netbeans.modules.j2ee.deployment.devmodules.spi.ResourceChangeReporterFactory;
import org.netbeans.modules.j2ee.deployment.devmodules.spi.ResourceChangeReporterImplementation;
import org.netbeans.modules.j2ee.earproject.model.ApplicationMetadataModelImpl;
import org.netbeans.modules.j2ee.earproject.ui.customizer.EarProjectProperties;
import org.netbeans.modules.j2ee.earproject.util.EarProjectUtil;
import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel;
import org.netbeans.modules.j2ee.metadata.model.spi.MetadataModelFactory;
import org.netbeans.modules.web.api.webmodule.WebModule;
import org.netbeans.spi.java.classpath.ClassPathProvider;
import org.openide.filesystems.FileChangeAdapter;
import org.openide.filesystems.FileEvent;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileRenameEvent;
import org.openide.filesystems.FileStateInvalidException;
import org.openide.filesystems.FileUtil;
import org.openide.util.Exceptions;
import org.openide.util.WeakListeners;
/**
* An enterprise application project's j2eeserver implementation
*
* @see ProjectEar
* @author vince kraemer
*/
public final class ProjectEar extends J2eeApplicationProvider
implements ModuleChangeReporter, EjbChangeDescriptor, PropertyChangeListener, J2eeApplicationImplementation2 {
public static final String FILE_DD = "application.xml";//NOI18N
private static final Logger LOGGER = Logger.getLogger(ProjectEar.class.getName());
private final ResourceChangeReporter rcr = ResourceChangeReporterFactory.createResourceChangeReporter(new EarResourceChangeReporter());
private final EarProject project;
private PropertyChangeSupport propertyChangeSupport;
private J2eeApplication j2eeApplication;
// XXX remove this property after metadata model is implemented
/* application reference for JAVA EE 5 only (if application.xml doesn't exist) */
private Application application;
private MetadataModel<ApplicationMetadata> metadataModel;
private final DeployOnSaveSupport deployOnSaveSupport = new DeployOnSaveSupportProxy();
final CopyOnSaveSupport copyOnSaveSupport = new CopyOnSaveSupport();
ProjectEar (EarProject project) { // ], AntProjectHelper helper) {
this.project = project;
}
/**
* Get the file object for deployment descriptor of EAR project.
* <b>Important note:</b> This method can return <code>null</code> (which is also default for JAVA EE 5).
* <p>
* This method should be used <b>only</b> when model is needed for writing.
* @return deployment descriptor or <code>null</null> when <i>application.xml</i>
* doesn't exists.
*/
public FileObject getDeploymentDescriptor() {
FileObject metaInf = getMetaInf();
if (metaInf != null) {
return metaInf.getFileObject(FILE_DD);
}
return null;
}
public FileObject getMetaInf() {
return project.getOrCreateMetaInfDir();
}
@Override
public File getResourceDirectory() {
File f = project.getFile(EarProjectProperties.RESOURCE_DIR);
if (f == null) {
f = new File(FileUtil.toFile(project.getProjectDirectory()), "setup"); // NOI18N
}
return f;
}
public ClassPathProvider getClassPathProvider () {
return project.getLookup().lookup(ClassPathProvider.class);
}
public FileObject getArchive () {
return project.getFileObject (EarProjectProperties.DIST_JAR); //NOI18N
}
public synchronized J2eeModule getJ2eeModule () {
if (j2eeApplication == null) {
j2eeApplication = J2eeModuleFactory.createJ2eeApplication(this);
}
return j2eeApplication;
}
public ModuleChangeReporter getModuleChangeReporter () {
return this;
}
@Override
public ResourceChangeReporter getResourceChangeReporter() {
return rcr;
}
@Override
public String getServerID () {
return project.getServerID(); //helper.getStandardPropertyEvaluator ().getProperty (EarProjectProperties.J2EE_SERVER_TYPE);
}
public void setServerInstanceID(String severInstanceID) {
// TODO: implement when needed
}
@Override
public String getServerInstanceID () {
return project.getServerInstanceID(); //helper.getStandardPropertyEvaluator ().getProperty (EarProjectProperties.J2EE_SERVER_INSTANCE);
}
/** Returns the contents of the archive, in copyable form.
* Used for incremental deployment. Currently uses its own J2eeModule.RootedEntry interface.
* If the J2eeModule instance describes a j2ee application, the result should not
* contain module archives.
*/
public Iterator getArchiveContents () throws IOException {
FileObject content = getContentDirectory();
content.refresh();
return new IT(this, content);
}
public FileObject getContentDirectory() {
return project.getFileObject (EarProjectProperties.BUILD_DIR); //NOI18N
}
public FileObject getBuildDirectory() {
return project.getFileObject (EarProjectProperties.BUILD_DIR); //NOI18N
}
/**
* Get metadata model of enterprise application.
*/
public synchronized MetadataModel<ApplicationMetadata> getMetadataModel() {
if (metadataModel == null) {
metadataModel = MetadataModelFactory.createMetadataModel(new ApplicationMetadataModelImpl(project));
}
return metadataModel;
}
public <T> MetadataModel<T> getMetadataModel(Class<T> type) {
if (type == ApplicationMetadata.class) {
@SuppressWarnings("unchecked") // NOI18N
MetadataModel<T> model = (MetadataModel<T>)getMetadataModel();
return model;
}
return null;
}
/**
* Get the metadata model of EAR project. The model is taken from deployment descriptor
* (<i>application.xml</i>) if it exists or is created on demand.
* <p>
* This method should be used whenever model is needed for reading or listening to changes
* but <b>not for writing</b>.
* @return metadata model.
*/
public Application getApplication() {
try {
// does application.xml exist?
if (DDHelper.isApplicationXMLCompulsory(project)
|| EarProjectUtil.isDDWritable(project)) {
// for JAVA EE 5 application.xml doesn't have to exist but can be generated on demand
// - so free resources if this is the case
if (!DDHelper.isApplicationXMLCompulsory(project)) {
synchronized (this) {
if (application != null) {
application = null;
}
}
}
return getDDFromFile();
}
// application.xml doesn't exist
return setupDDFromVirtual();
} catch (IOException ioe) {
Exceptions.printStackTrace(ioe);
}
// maybe exception?
return null;
}
private Application getDDFromFile() throws IOException {
FileObject dd = getDeploymentDescriptor();
if (dd == null) {
dd = EarProjectGenerator.setupDD(project.getJ2eeProfile(), getMetaInf(), project);
}
return DDProvider.getDefault().getDDRoot(dd);
}
// FIXME remove this after andrei's metadata model will be finished
private synchronized Application setupDDFromVirtual() throws IOException {
// application.xml exists?
if (EarProjectUtil.isDDWritable(project)) {
return getApplication();
}
// model already created
if (application != null) {
return application;
}
FileObject root = FileUtil.createMemoryFileSystem().getRoot();
Profile p = getJ2eeProfile();
if (p == null) {
p = Profile.JAVA_EE_7_FULL;
}
FileObject dd = DDHelper.createApplicationXml(p, root, true);
application = DDProvider.getDefault().getDDRoot(dd);
application.setDisplayName(ProjectUtils.getInformation(project).getDisplayName());
for (ClassPathSupport.Item item : EarProjectProperties.getJarContentAdditional(project)) {
EarProjectProperties.addItemToAppDD(project, application, item);
}
return application;
}
public EjbChangeDescriptor getEjbChanges (long timestamp) {
return this;
}
public J2eeModule.Type getModuleType () {
return J2eeModule.Type.EAR;
}
public String getModuleVersion () {
Profile p = Profile.fromPropertiesString(project.evaluator().getProperty(EarProjectProperties.J2EE_PLATFORM));
if (p == null) {
p = Profile.JAVA_EE_6_FULL;
}
if (Profile.JAVA_EE_5.equals(p)) {
return Application.VERSION_5;
} else if (Profile.J2EE_14.equals(p)) {
return Application.VERSION_1_4;
} else {
return Application.VERSION_6;
}
}
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(Application.PROPERTY_VERSION)) {
String oldVersion = (String) evt.getOldValue();
String newVersion = (String) evt.getNewValue();
getPropertyChangeSupport().firePropertyChange(J2eeModule.PROP_MODULE_VERSION, oldVersion, newVersion);
} else if (EarProjectProperties.J2EE_SERVER_INSTANCE.equals(evt.getPropertyName())) {
Deployment d = Deployment.getDefault();
String oldServerID = evt.getOldValue() == null ? null : d.getServerID((String)evt.getOldValue ());
String newServerID = evt.getNewValue() == null ? null : d.getServerID((String)evt.getNewValue ());
fireServerChange (oldServerID, newServerID);
} else if (EarProjectProperties.RESOURCE_DIR.equals(evt.getPropertyName())) {
String oldValue = (String)evt.getOldValue();
String newValue = (String)evt.getNewValue();
getPropertyChangeSupport().firePropertyChange(
J2eeModule.PROP_RESOURCE_DIRECTORY,
oldValue == null ? null : new File(oldValue),
newValue == null ? null : new File(newValue));
}
}
public String getUrl () {
return "";
}
public boolean isManifestChanged (long timestamp) {
return false;
}
public void setUrl (String url) {
throw new UnsupportedOperationException ("Cannot customize URL of web module"); // NOI18N
}
public boolean ejbsChanged () {
return false;
}
public String[] getChangedEjbs () {
return new String[] {};
}
public Profile getJ2eeProfile() {
return project.getJ2eeProfile();
}
@Override
public FileObject[] getSourceRoots() {
Sources sources = ProjectUtils.getSources(project);
SourceGroup[] groups = sources.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
FileObject[] roots = new FileObject[groups.length+1];
roots[0] = getMetaInf();
for (int i=0; i < groups.length; i++) {
roots[i+1] = groups[i].getRootFolder();
}
return roots;
}
private static class IT implements Iterator {
Iterator<FileObject> it;
FileObject root;
private IT(ProjectEar pe, FileObject f) {
J2eeModule mods[] = pe.getModules();
// build filter
Set<String> filter = new HashSet<String>(mods.length);
for (int i = 0; i < mods.length; i++) {
FileObject modArchive = null;
try {
modArchive = mods[i].getArchive();
} catch (java.io.IOException ioe) {
Logger.getLogger(ProjectEar.class.getName()).log(Level.FINER,
null,ioe);
continue;
}
if (modArchive != null) {
String modName = modArchive.getNameExt();
long modSize = modArchive.getSize();
filter.add(modName+"."+modSize); // NOI18N
}
}
ArrayList<FileObject> filteredContent = new ArrayList<FileObject>(5);
Enumeration ch = f.getChildren(true);
while (ch.hasMoreElements()) {
FileObject fo = (FileObject) ch.nextElement();
String fileName = fo.getNameExt();
long fileSize = fo.getSize();
if (filter.contains(fileName+"."+fileSize)) { // NOI18N
continue;
}
filteredContent.add(fo);
}
this.root = f;
it = filteredContent.iterator();
}
public boolean hasNext() {
return it.hasNext();
}
public Object next() {
return new FSRootRE(root, it.next());
}
public void remove () {
throw new UnsupportedOperationException ();
}
}
private static final class FSRootRE implements J2eeModule.RootedEntry {
FileObject f;
FileObject root;
FSRootRE (FileObject root, FileObject f) {
this.f = f;
this.root = root;
}
public FileObject getFileObject () {
return f;
}
public String getRelativePath () {
return FileUtil.getRelativePath (root, f);
}
}
private Map<String, J2eeModuleProvider> mods = new HashMap<String, J2eeModuleProvider>();
void setModules(Map<String, J2eeModuleProvider> mods) {
if (null == mods) {
throw new IllegalArgumentException("mods"); // NOI18N
}
this.mods = mods;
}
public J2eeModule[] getModules() {
J2eeModule[] retVal = new J2eeModule[mods.size()];
int i = 0;
for (J2eeModuleProvider provider : mods.values()) {
retVal[i++] = provider.getJ2eeModule();
}
return retVal;
}
public void addModuleProvider(J2eeModuleProvider jmp, String uri) {
mods.put(uri, jmp);
J2eeModule jm = jmp.getJ2eeModule();
fireAddModule(jm);
}
public void removeModuleProvider(J2eeModuleProvider jmp, String uri) {
// J2eeModuleProvider tmp = (J2eeModuleProvider) mods.get(uri);
// if (!tmp.equals(jmp)) {
// something fishy may be happening here
// XXX log it
// }
J2eeModule jm = jmp.getJ2eeModule();
fireRemoveModule(jm);
mods.remove(uri);
}
private final List<ModuleListener> modListeners = new ArrayList<ModuleListener>();
private void fireAddModule(J2eeModule jm) {
for (ModuleListener ml : modListeners) {
try {
ml.addModule(jm);
} catch (RuntimeException rex) {
Logger.getLogger("global").log(Level.INFO, rex.getLocalizedMessage());
}
}
}
private void fireRemoveModule(J2eeModule jm) {
for (ModuleListener ml : modListeners) {
try {
ml.removeModule(jm);
} catch (RuntimeException rex) {
Logger.getLogger("global").log(Level.FINE, rex.getLocalizedMessage());
}
}
}
public void addModuleListener(ModuleListener ml) {
modListeners.add(ml);
}
public void removeModuleListener(ModuleListener ml){
modListeners.remove(ml);
}
/**
* Returns the provider for the child module specified by given URI.
* @param uri the child module URI within the J2EE application.
* @return J2eeModuleProvider object
*/
public J2eeModuleProvider getChildModuleProvider(String uri) {
return mods.get(uri);
}
/**
* Returns list of providers of every child J2EE module of this J2EE app.
* @return array of J2eeModuleProvider objects.
*/
public J2eeModuleProvider[] getChildModuleProviders() {
return mods.values().toArray(new J2eeModuleProvider[mods.size()]);
}
@Override
public DeployOnSaveSupport getDeployOnSaveSupport() {
return deployOnSaveSupport;
}
@Override
public boolean isOnlyCompileOnSaveEnabled() {
return Boolean.parseBoolean(project.evaluator().getProperty(EarProjectProperties.J2EE_COMPILE_ON_SAVE)) &&
!Boolean.parseBoolean(project.evaluator().getProperty(EarProjectProperties.J2EE_DEPLOY_ON_SAVE));
}
public File getDeploymentConfigurationFile(String name) {
String path = getConfigSupport().getContentRelativePath(name);
if (path == null) {
path = name;
}
if (path.startsWith("META-INF/")) { // NOI18N
path = path.substring(8); // removing "META-INF/"
}
FileObject moduleFolder = getMetaInf();
if (moduleFolder == null) {
return null;
}
File configFolder = FileUtil.toFile(moduleFolder);
return new File(configFolder, path);
}
public void addEjbJarModule(EjbJar module) {
FileObject childFO = module.getDeploymentDescriptor();
if (childFO == null) {
childFO = module.getMetaInf();
}
addModule(childFO);
}
public void addWebModule(WebModule module) {
FileObject childFO = module.getDeploymentDescriptor();
if (childFO == null) {
childFO = module.getWebInf();
}
addModule(childFO);
}
public void addCarModule(Car module) {
FileObject childFO = module.getDeploymentDescriptor();
if (childFO == null) {
childFO = module.getMetaInf();
}
addModule(childFO);
}
private void addModule(final FileObject childFO) {
Project owner = null;
if (childFO != null) {
owner = FileOwnerQuery.getOwner(childFO);
}
if (owner == null) {
LOGGER.log(Level.INFO, "Unable to add module to the Enterpise Application. Owner project not found."); // NOI18N
} else {
EarProjectProperties.addJ2eeSubprojects(project, new Project [] {owner});
}
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
getPropertyChangeSupport().addPropertyChangeListener(listener);
}
public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
if (propertyChangeSupport == null) {
return;
}
propertyChangeSupport.removePropertyChangeListener(listener);
}
private PropertyChangeSupport getPropertyChangeSupport() {
Application app = getApplication();
synchronized (this) {
if (propertyChangeSupport == null) {
propertyChangeSupport = new PropertyChangeSupport(this);
if (app != null) {
PropertyChangeListener l = WeakListeners.create(PropertyChangeListener.class, this, app);
app.addPropertyChangeListener(l);
}
}
return propertyChangeSupport;
}
}
public J2eeModule getWebModule() {
for (J2eeModule mod : getModules()) {
if (mod.getType() == J2eeModule.Type.WAR) {
return mod;
}
}
return null;
}
/**
* This class handle copying of meta-inf resources to appropriate place in build
* dir. This class is used in true Deploy On Save.
*
* Class should not request project lock from FS listener methods
* (deadlock prone).
*/
public class CopyOnSaveSupport extends FileChangeAdapter implements PropertyChangeListener, ConfigSupport.DeployOnSaveListener {
private File resources = null;
private final List<ArtifactListener> listeners = new CopyOnWriteArrayList<ArtifactListener>();
/** Creates a new instance of CopyOnSaveSupport */
public CopyOnSaveSupport() {
super();
}
public void addArtifactListener(ArtifactListener listener) {
listeners.add(listener);
}
public void removeArtifactListener(ArtifactListener listener) {
listeners.remove(listener);
}
private boolean isCopyOnSaveEnabled() {
return Boolean.parseBoolean(ProjectEar.this.project.evaluator().getProperty(EarProjectProperties.J2EE_COMPILE_ON_SAVE));
}
public void initialize() throws FileStateInvalidException {
ProjectEar.this.project.evaluator().addPropertyChangeListener(this);
if (!isCopyOnSaveEnabled()) {
return;
}
if (resources != null) {
FileUtil.removeFileChangeListener(this, resources);
}
resources = getResourceDirectory();
if (resources != null) {
FileUtil.addFileChangeListener(this, resources);
}
// Add deployed resources notification listener
ProjectEar.this.getConfigSupport().addDeployOnSaveListener(this);
}
public void cleanup() throws FileStateInvalidException {
if (resources != null) {
FileUtil.removeFileChangeListener(this, resources);
resources = null;
}
ProjectEar.this.project.evaluator().removePropertyChangeListener(this);
ProjectEar.this.getConfigSupport().removeDeployOnSaveListener(this);
}
public void propertyChange(PropertyChangeEvent evt) {
if (EarProjectProperties.RESOURCE_DIR.equals(evt.getPropertyName()) ||
EarProjectProperties.J2EE_COMPILE_ON_SAVE.equals(evt.getPropertyName())) {
try {
cleanup();
initialize();
} catch (org.openide.filesystems.FileStateInvalidException e) {
LOGGER.log(Level.INFO, null, e);
}
}
}
@Override
public void fileChanged(FileEvent fe) {
handleResource(fe);
}
@Override
public void fileDataCreated(FileEvent fe) {
handleResource(fe);
}
@Override
public void fileRenamed(FileRenameEvent fe) {
handleResource(fe);
}
@Override
public void fileDeleted(FileEvent fe) {
handleResource(fe);
}
private void fireArtifactChange(Iterable<ArtifactListener.Artifact> files) {
for (ArtifactListener listener : listeners) {
listener.artifactsUpdated(files);
}
}
private void handleResource(FileEvent fe) {
// this may happen in broken project - see issue #191516
// in any case it can't be resource event when resources is null
if (resources == null) {
return;
}
FileObject resourceFo = FileUtil.toFileObject(resources);
if (resourceFo != null
&& (resourceFo.equals(fe.getFile()) || FileUtil.isParentOf(resourceFo, fe.getFile()))) {
fireArtifactChange(Collections.singleton(
Artifact.forFile(FileUtil.toFile(fe.getFile())).serverResource()));
}
}
@Override
public void deployed(Iterable<Artifact> artifacts) {
if (project.getLookup().lookup(WebBrowserProvider.class) == null ||
!project.getEaselSupport().canReload()) {
return;
}
for (Artifact artifact : artifacts) {
FileObject fileObject = getReloadFileObject(artifact);
if (fileObject != null) {
project.getEaselSupport().reload(fileObject);
}
}
}
private FileObject getReloadFileObject(Artifact artifact) {
File file = artifact.getFile();
FileObject fileObject = FileUtil.toFileObject(FileUtil.normalizeFile(file));
if (fileObject == null) {
return null;
}
try {
return findSourceForBinary(fileObject);
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
return null;
}
}
// "Binary" means compiled class file or web root document copied into build directory
private FileObject findSourceForBinary(FileObject artifact) throws IOException {
WebModule wm = WebModule.getWebModule(artifact);
if (wm == null) {
return null;
}
J2eeModule mod = getWebModule();
if (mod != null) {
FileObject contentDir = mod.getContentDirectory();
if (contentDir != null) {
// TODO: any chance of doing this properly via an API?
FileObject classesDir = contentDir.getFileObject("WEB-INF/classes"); // NOI18N
Project p = FileOwnerQuery.getOwner(artifact);
if (p != null && classesDir != null && FileUtil.isParentOf(classesDir, artifact)) {
String path = FileUtil.getRelativePath(classesDir, artifact).replace(".class", ".java"); // NOI18N
for (SourceGroup sg : ProjectUtils.getSources(p).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA)) {
FileObject fo = sg.getRootFolder().getFileObject(path);
if (fo != null) {
return fo;
}
}
return null;
}
FileObject docBase = wm.getDocumentBase();
if (docBase != null && FileUtil.isParentOf(contentDir, artifact)) {
String path = FileUtil.getRelativePath(contentDir, artifact);
return docBase.getFileObject(path);
}
}
}
return null;
}
}
/**
* This class is proxying events from child listeners and perform
* <i>library-inclusion-in-manifest</i> (out of EJB and WEB) logic. Soo ugly but
* inevitable :(
*/
private class DeployOnSaveSupportProxy implements ArtifactListener, DeployOnSaveSupport {
private final List<ArtifactListener> listeners = new ArrayList<ArtifactListener>();
public DeployOnSaveSupportProxy() {
super();
}
public synchronized void addArtifactListener(ArtifactListener listener) {
copyOnSaveSupport.addArtifactListener(listener);
boolean register = listeners.isEmpty();
if (listener != null) {
listeners.add(listener);
}
if (register) {
for (J2eeModuleProvider provider : getChildModuleProviders()) {
DeployOnSaveSupport support = provider.getDeployOnSaveSupport();
if (support != null) {
support.addArtifactListener(this);
}
}
}
}
public synchronized void removeArtifactListener(ArtifactListener listener) {
copyOnSaveSupport.removeArtifactListener(listener);
if (listener != null) {
listeners.remove(listener);
}
if (listeners.isEmpty()) {
for (J2eeModuleProvider provider : getChildModuleProviders()) {
DeployOnSaveSupport support = provider.getDeployOnSaveSupport();
if (support != null) {
support.removeArtifactListener(this);
}
}
}
}
public boolean containsIdeArtifacts() {
for (J2eeModuleProvider provider : getChildModuleProviders()) {
DeployOnSaveSupport support = provider.getDeployOnSaveSupport();
if (support != null) {
if (support.containsIdeArtifacts()) {
return true;
}
}
}
return false;
}
public void artifactsUpdated(Iterable<Artifact> artifacts) {
List<Artifact> recomputed = new ArrayList<Artifact>();
String buildDirName = project.evaluator().getProperty(EarProjectProperties.BUILD_DIR);
if (buildDirName == null) {
return;
}
for (Artifact artifact : artifacts) {
if (artifact.isReferencedLibrary() && artifact.isRelocatable()) {
// FIXME manifest ant TLD magic
File buildDir = project.getAntProjectHelper().resolveFile(
buildDirName);
String relocation = artifact.getRelocation();
File destFile = null;
if (relocation != null) {
destFile = new File(buildDir, relocation + File.separator
+ artifact.getFile().getName());
} else {
destFile = new File(buildDir, artifact.getFile().getName());
}
try {
FileUtil.createData(destFile);
} catch (IOException ex) {
LOGGER.log(Level.INFO, "Could not prepare data file", ex);
continue;
}
recomputed.add(artifact.distributionPath(destFile));
} else {
recomputed.add(artifact);
}
}
List<ArtifactListener> toFire = null;
synchronized (this) {
toFire = new ArrayList<ArtifactListener>(listeners);
}
for (ArtifactListener listener : toFire) {
listener.artifactsUpdated(recomputed);
}
}
}
private class EarResourceChangeReporter implements ResourceChangeReporterImplementation {
public boolean isServerResourceChanged(long lastDeploy) {
File resDir = getResourceDirectory();
if (resDir != null && resDir.exists() && resDir.isDirectory()) {
File[] children = resDir.listFiles();
if (children != null) {
for (File file : children) {
if (file.lastModified() > lastDeploy) {
return true;
}
}
}
}
return false;
}
}
}