/*
* 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.apache.sling.ide.eclipse.core.internal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.sling.ide.log.Logger;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.wst.common.project.facet.core.IFacetedProject;
import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion;
import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager;
import org.eclipse.wst.server.core.IModule;
import org.eclipse.wst.server.core.model.IModuleResource;
import org.eclipse.wst.server.core.model.ModuleDelegate;
import org.eclipse.wst.server.core.util.ModuleFile;
import org.eclipse.wst.server.core.util.ProjectModule;
import org.eclipse.wst.server.core.util.ProjectModuleFactoryDelegate;
public class SlingBundleModuleFactory extends ProjectModuleFactoryDelegate {
static final String SLING_BUNDLE_FACET_ID = "sling.bundle";
private static final IPath[] SETTINGS_PATHS = new IPath[] {new Path(".settings")};
@Override
public IModule[] getModules(IProject project) {
final IModule[] result = super.getModules(project);
if (result!=null && result.length>0) {
return result;
} else {
// try clearing the cache
// might fix SLING-3663 which could be due to a synchronization issue at first access time
clearCache(project);
return super.getModules(project);
}
}
@Override
protected IPath[] getListenerPaths() {
// returning the .settings path instead of null (as done by the parent)
// results in clearing the cache on changes to .settings - which in turn
// results in re-evaluating facet changes.
// we could be more specific here but .settings changes are infrequent anyway.
return SETTINGS_PATHS;
}
@Override
public ModuleDelegate getModuleDelegate(IModule module) {
return new SlingBundleModuleDelegate(module);
}
@Override
protected IModule createModule(IProject project) {
try {
IFacetedProject facetedProject = ProjectFacetsManager.create(project);
if (facetedProject == null) {
return null;
}
for (IProjectFacetVersion facet : facetedProject.getProjectFacets()) {
if (facet.getProjectFacet().getId().equals(SLING_BUNDLE_FACET_ID)) {
return createModule(project.getName(), project.getName(), SLING_BUNDLE_FACET_ID, "1.0", project);
}
}
} catch (CoreException ce) {
Activator.getDefault().getPluginLogger().warn("Failed creating module for project " + project, ce);
}
return null;
}
static class SlingBundleModuleDelegate extends ProjectModule {
private static final IModule[] EMPTY_MODULES = new IModule[0];
public SlingBundleModuleDelegate(IModule module) {
super(module.getProject());
}
@Override
public IStatus validate() {
return Status.OK_STATUS; // TODO actually validate
}
/**
* This returns the list of module resources that make up the bundle.
* <p>
* This list is composed of all files which are not derived. Derived files
* are those that are generated by m2eclipse/eclipse - and typically are
* the derived files and/or the files under target/classes (the output dirs).
* <p>
* This list is further down used as the input to SlingLaunchpadBehaviour
* and there evaluated. Depending on that class's behavior, this method
* might have to be adjusted (as for example in one version the SlingLaunchpadBehaviour
* completely ignores the list of changed files and redeploys everything - if another
* behaviour is used where only diffs are published, this members might have
* to return exactly the opposite: everything derived..)
*/
@Override
public IModuleResource[] members() throws CoreException {
final IJavaProject javaProject = ProjectHelper.asJavaProject(getProject());
final List<IModuleResource> resources = new ArrayList<>();
final Set<String> filteredLocations = new HashSet<>();
final IJavaProject jp = javaProject;
final IClasspathEntry[] rawCp = jp.getRawClasspath();
for (int i = 0; i < rawCp.length; i++) {
IClasspathEntry aCp = rawCp[i];
IPath outputLocation = aCp.getOutputLocation();
if (outputLocation!=null) {
outputLocation = outputLocation.makeRelativeTo(getProject().getFullPath());
filteredLocations.add(outputLocation.toString());
}
}
getProject().accept(new IResourceVisitor() {
@Override
public boolean visit(IResource resource) throws CoreException {
if (resource.getType() == IResource.PROJECT) {
return true;
}
final IPath relativePath = resource.getProjectRelativePath();
if (relativePath == null) {
return false;
}
final String relPathStr = relativePath.toString();
if (relPathStr == null || relPathStr.length()==0) {
return false;
}
if (resource.isDerived()) {
// then dont accept it
return false;
}
if (filteredLocations.contains(relPathStr)) {
return false;
}
if (resource.getType() == IResource.FILE) {
// the bundle facet accepts all files that are not in the output directory/derived
ModuleFile moduleFile = new ModuleFile((IFile) resource, resource.getName(), relativePath);
resources.add(moduleFile);
}
return true;
}
});
Logger logger = Activator.getDefault().getPluginLogger();
for (Iterator<IModuleResource> it = resources.iterator(); it.hasNext();) {
IModuleResource iModuleResource = it.next();
logger.trace("For module {0} added {1}", getName(), iModuleResource.getModuleRelativePath()
.toString());
}
return resources.toArray(new IModuleResource[resources.size()]);
}
@Override
public IModule[] getChildModules() {
return EMPTY_MODULES;
}
}
}