Author: rombert
Date: Fri May 23 12:07:17 2014
New Revision: 1597070

URL: http://svn.apache.org/r1597070
Log:
SLING-3550 - Inspect bundles for deployment for well-known errors

Add a BundleProjectValidator which inspects the Service-Component
header.

Added:
    
sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/internal/
    
sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/internal/validation/
    
sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/internal/validation/BundleProjectValidator.java
   (with props)
    
sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/internal/validation/ServiceComponentHeaderValidator.java
   (with props)
    
sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/ServiceComponentHeaderValidatorTest.java
   (with props)
Modified:
    sling/trunk/tooling/ide/eclipse-core/META-INF/MANIFEST.MF
    sling/trunk/tooling/ide/eclipse-core/plugin.xml
    
sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/helpers/EclipseResourceMatchers.java
    
sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/helpers/HasFileMatcher.java

Modified: sling/trunk/tooling/ide/eclipse-core/META-INF/MANIFEST.MF
URL: 
http://svn.apache.org/viewvc/sling/trunk/tooling/ide/eclipse-core/META-INF/MANIFEST.MF?rev=1597070&r1=1597069&r2=1597070&view=diff
==============================================================================
--- sling/trunk/tooling/ide/eclipse-core/META-INF/MANIFEST.MF (original)
+++ sling/trunk/tooling/ide/eclipse-core/META-INF/MANIFEST.MF Fri May 23 
12:07:17 2014
@@ -38,8 +38,10 @@ Import-Package: org.apache.commons.httpc
  org.eclipse.wst.server.core,
  org.eclipse.wst.server.core.model,
  org.eclipse.wst.server.core.util,
+ org.eclipse.wst.validation,
  org.json,
  org.osgi.service.component;version="1.1.0"
 Export-Package: org.apache.sling.ide.eclipse.core,
  org.apache.sling.ide.eclipse.core.internal,
- org.apache.sling.ide.eclipse.core.debug
+ org.apache.sling.ide.eclipse.core.debug,
+ 
org.apache.sling.ide.eclipse.internal.validation;x-friends:=org.apache.sling.ide.eclipse-test

Modified: sling/trunk/tooling/ide/eclipse-core/plugin.xml
URL: 
http://svn.apache.org/viewvc/sling/trunk/tooling/ide/eclipse-core/plugin.xml?rev=1597070&r1=1597069&r2=1597070&view=diff
==============================================================================
--- sling/trunk/tooling/ide/eclipse-core/plugin.xml (original)
+++ sling/trunk/tooling/ide/eclipse-core/plugin.xml Fri May 23 12:07:17 2014
@@ -181,5 +181,20 @@
                properties="canBeExported,canBeImported"
                
class="org.apache.sling.ide.eclipse.core.internal.ContentResourceTester">
          </propertyTester>
-   </extension>    
+   </extension>
+   
+   <extension
+         id="bundleValidator"
+         point="org.eclipse.wst.validation.validatorV2"
+         name="Sling Bundle Validator">
+      <validator 
class="org.apache.sling.ide.eclipse.internal.validation.BundleProjectValidator">
+       <include>
+          <rules>
+               <facet
+                 id="sling.bundle">
+               </facet>
+          </rules>
+       </include>
+      </validator>
+   </extension>
 </plugin>    

Added: 
sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/internal/validation/BundleProjectValidator.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/internal/validation/BundleProjectValidator.java?rev=1597070&view=auto
==============================================================================
--- 
sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/internal/validation/BundleProjectValidator.java
 (added)
+++ 
sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/internal/validation/BundleProjectValidator.java
 Fri May 23 12:07:17 2014
@@ -0,0 +1,69 @@
+/*
+ * 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.internal.validation;
+
+import org.apache.sling.ide.eclipse.core.debug.PluginLogger;
+import org.apache.sling.ide.eclipse.core.internal.Activator;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.wst.validation.AbstractValidator;
+import org.eclipse.wst.validation.ValidationEvent;
+import org.eclipse.wst.validation.ValidationResult;
+import org.eclipse.wst.validation.ValidationState;
+import org.eclipse.wst.validation.ValidatorMessage;
+
+public class BundleProjectValidator extends AbstractValidator {
+
+    private final ServiceComponentHeaderValidator scValidator = new 
ServiceComponentHeaderValidator();
+
+    @Override
+    public ValidationResult validate(ValidationEvent event, ValidationState 
state, IProgressMonitor monitor) {
+        
+        ValidationResult res = new ValidationResult();
+
+        IResource resource = event.getResource();
+
+        if (!resource.getName().equals("MANIFEST.MF") || resource.getType() != 
IResource.FILE) {
+            return res;
+        }
+
+        IFile m = (IFile) resource;
+
+        PluginLogger pluginLogger = Activator.getDefault() .getPluginLogger();
+
+        try {
+
+            for (IFile descriptor : scValidator.findMissingScrDescriptors(m)) {
+                ValidatorMessage dsMessage = ValidatorMessage.create(
+                        "No DS descriptor found at path " + 
descriptor.getProjectRelativePath(), m);
+                dsMessage.setAttribute(IMarker.LOCATION, m.getName());
+                dsMessage.setAttribute(IMarker.SEVERITY, 
IMarker.SEVERITY_ERROR);
+
+                res.add(dsMessage);
+
+            }
+
+        } catch (CoreException e) {
+            pluginLogger.warn("Failed validating project " + 
resource.getFullPath(), e);
+        }
+        
+        return res;
+    }
+}

Propchange: 
sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/internal/validation/BundleProjectValidator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/internal/validation/BundleProjectValidator.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: 
sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/internal/validation/ServiceComponentHeaderValidator.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/internal/validation/ServiceComponentHeaderValidator.java?rev=1597070&view=auto
==============================================================================
--- 
sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/internal/validation/ServiceComponentHeaderValidator.java
 (added)
+++ 
sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/internal/validation/ServiceComponentHeaderValidator.java
 Fri May 23 12:07:17 2014
@@ -0,0 +1,104 @@
+/*
+ * 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.internal.validation;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.jar.Manifest;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.sling.ide.eclipse.core.debug.PluginLogger;
+import org.apache.sling.ide.eclipse.core.internal.Activator;
+import org.apache.sling.ide.eclipse.core.internal.ProjectHelper;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jdt.core.IJavaProject;
+
+public class ServiceComponentHeaderValidator {
+
+    /**
+     * Finds missing SCR descriptor files referenced in the manifest
+     * 
+     * <p>
+     * Only acts if the Manifest is located under the project's output 
directory at
+     * </p>
+     * 
+     * @param manifest the location of the manifest to parse for the 
Service-Component header
+     * @return a list of missing files, empty if no problems are found
+     * @throws CoreException any errors
+     */
+    public List<IFile> findMissingScrDescriptors(IFile manifest) throws 
CoreException {
+
+        IProject project = manifest.getProject();
+
+        PluginLogger pluginLogger = Activator.getDefault().getPluginLogger();
+
+        IJavaProject javaProject = ProjectHelper.asJavaProject(project);
+
+        IFolder outputFolder = (IFolder) 
project.getWorkspace().getRoot().findMember(javaProject.getOutputLocation());
+
+        if (!outputFolder.getFullPath().isPrefixOf(manifest.getFullPath())) {
+            pluginLogger.trace("Ignoring manifest found at {0} since it is not 
under the output directory at {1}",
+                    manifest.getFullPath(), outputFolder.getFullPath());
+            return Collections.emptyList();
+        }
+
+        List<IFile> missingDescriptors = new ArrayList<IFile>();
+
+        InputStream contents = manifest.getContents();
+        try {
+            Manifest mf = new Manifest(contents);
+            String serviceComponentHeader = 
mf.getMainAttributes().getValue("Service-Component");
+            if (serviceComponentHeader != null) {
+                String[] entries = serviceComponentHeader.split(",");
+                for (String entry : entries) {
+                    entry = entry.trim();
+
+                    if (entry.contains("*")) {
+                        pluginLogger.trace("Ignoring wildcard 
Service-Component entry {0}", entry);
+                        continue;
+                    }
+
+                    IFile descriptor = outputFolder.getFile(entry);
+
+                    if (descriptor.exists()) {
+                        pluginLogger.trace("Found matching resource for 
Service-Component entry {0}", entry);
+                        continue;
+                    }
+
+                    missingDescriptors.add(descriptor);
+
+                    pluginLogger.trace("Raising error for missing DS 
descriptor entry {0}", entry);
+                }
+            }
+        } catch (IOException e) {
+            throw new CoreException(new Status(IStatus.ERROR, 
Activator.PLUGIN_ID, "Unable to access "
+                    + manifest.getFullPath(), e));
+        } finally {
+            IOUtils.closeQuietly(contents);
+        }
+
+        return missingDescriptors;
+    }
+}

Propchange: 
sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/internal/validation/ServiceComponentHeaderValidator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/tooling/ide/eclipse-core/src/org/apache/sling/ide/eclipse/internal/validation/ServiceComponentHeaderValidator.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: 
sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/ServiceComponentHeaderValidatorTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/ServiceComponentHeaderValidatorTest.java?rev=1597070&view=auto
==============================================================================
--- 
sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/ServiceComponentHeaderValidatorTest.java
 (added)
+++ 
sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/ServiceComponentHeaderValidatorTest.java
 Fri May 23 12:07:17 2014
@@ -0,0 +1,135 @@
+/*
+ * 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.test.impl;
+
+import static 
org.apache.sling.ide.test.impl.helpers.EclipseResourceMatchers.hasFile;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import 
org.apache.sling.ide.eclipse.internal.validation.ServiceComponentHeaderValidator;
+import org.apache.sling.ide.test.impl.helpers.OsgiBundleManifest;
+import org.apache.sling.ide.test.impl.helpers.Poller;
+import org.apache.sling.ide.test.impl.helpers.ProjectAdapter;
+import org.apache.sling.ide.test.impl.helpers.TemporaryProject;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.JavaCore;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class ServiceComponentHeaderValidatorTest {
+
+    @Rule
+    public TemporaryProject projectRule = new TemporaryProject();
+    private ProjectAdapter project;
+    private Poller poller;
+
+    @Test
+    public void missingDescriptorIsReported() throws CoreException, 
IOException, InterruptedException {
+
+        String sch = "OSGI-INF/descriptor1.xml, OSGI-INF/descriptor2.xml";
+        
+        createJavaProject(sch);
+
+        ServiceComponentHeaderValidator validator = new 
ServiceComponentHeaderValidator();
+        List<IFile> missingDescriptors = 
validator.findMissingScrDescriptors(projectRule.getProject().getFile(
+                "bin/META-INF/MANIFEST.MF"));
+
+        assertThat("missingDescriptors.size", missingDescriptors.size(), 
equalTo(2));
+        assertThat("missingDescriptors[0].projectRelativePath", 
missingDescriptors.get(0).getProjectRelativePath(),
+                
equalTo(Path.fromPortableString("bin/OSGI-INF/descriptor1.xml")));
+        assertThat("missingDescriptors[0].projectRelativePath", 
missingDescriptors.get(1).getProjectRelativePath(),
+                
equalTo(Path.fromPortableString("bin/OSGI-INF/descriptor2.xml")));
+    }
+
+    private void createJavaProject(String serviceComponentHeader) throws 
CoreException, IOException,
+            InterruptedException {
+
+        project = new ProjectAdapter(projectRule.getProject());
+        project.addNatures(JavaCore.NATURE_ID);
+        project.configureAsJavaProject();
+
+        OsgiBundleManifest mf = new 
OsgiBundleManifest("com.example.bundle001").version("1.0.0").serviceComponent(
+                serviceComponentHeader);
+
+        project.createOsgiBundleManifest(mf);
+
+        poller = new Poller();
+        poller.pollUntil(new Callable<IProject>() {
+
+            @Override
+            public IProject call() throws Exception {
+                return projectRule.getProject();
+            }
+        }, hasFile("bin/META-INF/MANIFEST.MF"));
+    }
+
+    @Test
+    public void wildCardHeaderIsIgnored() throws CoreException, IOException, 
InterruptedException {
+
+        createJavaProject("OSGI-INF/*.xml");
+
+        ServiceComponentHeaderValidator validator = new 
ServiceComponentHeaderValidator();
+        List<IFile> missingDescriptors = 
validator.findMissingScrDescriptors(projectRule.getProject().getFile(
+                "bin/META-INF/MANIFEST.MF"));
+
+        assertThat("missingDescriptors.size", missingDescriptors.size(), 
equalTo(0));
+    }
+
+    @Test
+    public void presentDescriptorIsNotReported() throws CoreException, 
IOException, InterruptedException {
+
+        createJavaProject("OSGI-INF/descriptor.xml");
+
+        
project.createOrUpdateFile(Path.fromPortableString("src/OSGI-INF/descriptor.xml"),
 new ByteArrayInputStream(
+                "<!-- does not matter -->".getBytes()));
+
+        poller.pollUntil(new Callable<IProject>() {
+
+            @Override
+            public IProject call() throws Exception {
+                return projectRule.getProject();
+            }
+        }, hasFile("bin/OSGI-INF/descriptor.xml"));
+
+        ServiceComponentHeaderValidator validator = new 
ServiceComponentHeaderValidator();
+        List<IFile> missingDescriptors = 
validator.findMissingScrDescriptors(projectRule.getProject().getFile(
+                "bin/META-INF/MANIFEST.MF"));
+
+        assertThat("missingDescriptors.size", missingDescriptors.size(), 
equalTo(0));
+    }
+
+    @Test
+    public void manifestNotUnderOutputDirectoryIsIgnored() throws 
CoreException, IOException, InterruptedException {
+
+        createJavaProject("OSGI-INF/descriptor.xml");
+
+        ServiceComponentHeaderValidator validator = new 
ServiceComponentHeaderValidator();
+        List<IFile> missingDescriptors = 
validator.findMissingScrDescriptors(projectRule.getProject().getFile(
+                "src/META-INF/MANIFEST.MF"));
+
+        assertThat("missingDescriptors.size", missingDescriptors.size(), 
equalTo(0));
+    }
+
+}

Propchange: 
sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/ServiceComponentHeaderValidatorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/ServiceComponentHeaderValidatorTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Modified: 
sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/helpers/EclipseResourceMatchers.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/helpers/EclipseResourceMatchers.java?rev=1597070&r1=1597069&r2=1597070&view=diff
==============================================================================
--- 
sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/helpers/EclipseResourceMatchers.java
 (original)
+++ 
sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/helpers/EclipseResourceMatchers.java
 Fri May 23 12:07:17 2014
@@ -25,6 +25,10 @@ public class EclipseResourceMatchers {
         return new HasFileMatcher(path, contents);
     }
 
+    public static Matcher<IProject> hasFile(String path) {
+        return new HasFileMatcher(path, null);
+    }
+
     public static Matcher<IProject> hasFolder(String path) {
         return new HasFolderMatcher(path);
     }

Modified: 
sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/helpers/HasFileMatcher.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/helpers/HasFileMatcher.java?rev=1597070&r1=1597069&r2=1597070&view=diff
==============================================================================
--- 
sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/helpers/HasFileMatcher.java
 (original)
+++ 
sling/trunk/tooling/ide/eclipse-test/src/org/apache/sling/ide/test/impl/helpers/HasFileMatcher.java
 Fri May 23 12:07:17 2014
@@ -31,10 +31,6 @@ import org.hamcrest.TypeSafeMatcher;
 
 public class HasFileMatcher extends TypeSafeMatcher<IProject> {
 
-    public static final HasFileMatcher hasFile(String filePath, byte[] 
contents) {
-        return new HasFileMatcher(filePath, contents);
-    }
-
     private final String fileName;
     private final byte[] contents;
 
@@ -66,6 +62,10 @@ public class HasFileMatcher extends Type
             return false;
         }
 
+        if (contents == null) {
+            return true;
+        }
+
         IFile file = (IFile) maybeFile;
         ByteArrayOutputStream out = new ByteArrayOutputStream();
 


Reply via email to