felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cziege...@apache.org
Subject svn commit: r562420 [1/3] - in /felix/sandbox/cziegeler/maven-scr-plugin: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/sandbox/ src/main/java/org/apache/fel...
Date Fri, 03 Aug 2007 12:07:48 GMT
Author: cziegeler
Date: Fri Aug  3 05:07:45 2007
New Revision: 562420

URL: http://svn.apache.org/viewvc?view=rev&rev=562420
Log:
Initial check-in for a new maven-scr-plugin.

Added:
    felix/sandbox/cziegeler/maven-scr-plugin/
    felix/sandbox/cziegeler/maven-scr-plugin/pom.xml   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/AbstractDescriptorElement.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Property.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Reference.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/SCRDescriptor.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/SCRDescriptorMojo.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Service.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/XMLWriter.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/JavaClassDescription.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/JavaClassDescriptorManager.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/JavaField.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/JavaMethod.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/JavaParameter.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/JavaTag.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/cl/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/cl/ClassLoaderJavaClassDescription.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/cl/ClassLoaderJavaMethod.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/cl/ClassLoaderJavaParameter.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/cl/ClassLoaderJavaTag.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/qdox/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/qdox/QDoxJavaClassDescription.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/qdox/QDoxJavaField.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/qdox/QDoxJavaMethod.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/qdox/QDoxJavaParameter.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/qdox/QDoxJavaTag.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/xml/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/xml/Component.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/xml/Components.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/xml/Implementation.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/xml/Interface.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/xml/Property.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/xml/Reference.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/xml/Service.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/xml/XMLHandler.java   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/resources/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/resources/org/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/resources/org/apache/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/resources/org/apache/felix/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/resources/org/apache/felix/sandbox/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/resources/org/apache/felix/sandbox/scrplugin/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/resources/org/apache/felix/sandbox/scrplugin/xml/
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/resources/org/apache/felix/sandbox/scrplugin/xml/read.xsl   (with props)
    felix/sandbox/cziegeler/maven-scr-plugin/src/main/resources/org/apache/felix/sandbox/scrplugin/xml/write.xsl   (with props)

Added: felix/sandbox/cziegeler/maven-scr-plugin/pom.xml
URL: http://svn.apache.org/viewvc/felix/sandbox/cziegeler/maven-scr-plugin/pom.xml?view=auto&rev=562420
==============================================================================
--- felix/sandbox/cziegeler/maven-scr-plugin/pom.xml (added)
+++ felix/sandbox/cziegeler/maven-scr-plugin/pom.xml Fri Aug  3 05:07:45 2007
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>felix</artifactId>
+        <groupId>org.apache.felix</groupId>
+        <version>1.0.0</version>
+    </parent>
+
+    <groupId>org.apache.felix</groupId>
+    <artifactId>maven-scr-plugin</artifactId>
+
+	<version>0.1.0-SNAPSHOT</version>
+	<packaging>maven-plugin</packaging>
+
+	<name>Maven Scr Plugin</name>
+	<description>
+		Maven plugin for generating OSGi service descriptors based on annotations.
+	</description>
+
+	<scm>
+		<connection>scm:svn:http://svn.apache.org/repos/asf/felix/trunk/maven-scr-plugin</connection>
+		<developerConnection>scm:svn:http://svn.apache.org/repos/asf/felix/trunk/maven-scr-plugin</developerConnection>
+		<url>http://svn.apache.org/repos/asf/felix/maven-scr-plugin</url>
+	</scm>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.osgi</groupId>
+			<artifactId>osgi_R4_core</artifactId>
+			<version>1.0</version>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.osgi</groupId>
+			<artifactId>osgi_R4_compendium</artifactId>
+			<version>1.0</version>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+		    <groupId>org.apache.commons</groupId>
+		    <artifactId>commons-io</artifactId>
+		    <version>1.3.2</version>
+		</dependency>
+        <dependency>
+            <groupId>com.thoughtworks.xstream</groupId>
+            <artifactId>xstream</artifactId>
+            <version>1.2.2</version>
+        </dependency>
+
+		<dependency>
+			<groupId>org.apache.maven</groupId>
+			<artifactId>maven-plugin-api</artifactId>
+			<version>2.0.7</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.maven</groupId>
+			<artifactId>maven-archiver</artifactId>
+			<version>2.2</version>
+		</dependency>
+
+		<dependency>
+			<groupId>com.thoughtworks.qdox</groupId>
+			<artifactId>qdox</artifactId>
+			<version>1.6.3</version>
+		</dependency>
+	</dependencies>
+</project>

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/pom.xml
------------------------------------------------------------------------------
    svn:keywords = Id

Added: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/AbstractDescriptorElement.java
URL: http://svn.apache.org/viewvc/felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/AbstractDescriptorElement.java?view=auto&rev=562420
==============================================================================
--- felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/AbstractDescriptorElement.java (added)
+++ felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/AbstractDescriptorElement.java Fri Aug  3 05:07:45 2007
@@ -0,0 +1,51 @@
+/*
+ * 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.felix.sandbox.scrplugin;
+
+import org.apache.felix.sandbox.scrplugin.tags.JavaTag;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+
+/**
+ * The <code>AbstractDescriptorElement</code>
+ * is the base class for the all classes of the scr om.
+ */
+abstract class AbstractDescriptorElement {
+
+    private final Log log;
+
+    protected final JavaTag tag;
+
+    protected AbstractDescriptorElement(Log log, JavaTag tag) {
+        this.log = log;
+        this.tag = tag;
+    }
+
+    abstract boolean validate() throws MojoExecutionException;
+
+    abstract void generate(XMLWriter xmlWriter);
+
+    protected void log(String message) {
+        this.log.error("@" + this.tag.getName() + ": " + message + " (" + this.tag.getSourceLocation() + ")");
+    }
+
+    protected void warn(String message) {
+        this.log.warn(message);
+    }
+}

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/AbstractDescriptorElement.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/AbstractDescriptorElement.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Property.java
URL: http://svn.apache.org/viewvc/felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Property.java?view=auto&rev=562420
==============================================================================
--- felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Property.java (added)
+++ felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Property.java Fri Aug  3 05:07:45 2007
@@ -0,0 +1,272 @@
+/*
+ * 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.felix.sandbox.scrplugin;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.sandbox.scrplugin.tags.JavaTag;
+import org.apache.maven.plugin.logging.Log;
+import org.codehaus.plexus.util.StringUtils;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+/**
+ * Model: scr property
+ */
+public class Property extends AbstractDescriptorElement implements Comparable {
+
+    private String name = "";
+
+    private String label;
+
+    private String description;
+
+    private int cardinality;
+
+    private String type = "String";
+
+    private Object value;
+
+    private boolean privateProperty;
+
+    private Map options;
+
+    Property(Log log, JavaTag tag) {
+        super(log, tag);
+    }
+
+    boolean validate() {
+        // might want to check name and type
+        return true;
+    }
+
+    void generate(XMLWriter xw) {
+        xw.printElementStart("property", true);
+        xw.printAttribute("name", this.getName());
+        if (!"String".equals(this.getType())) xw.printAttribute("type", this.getType());
+
+        if (this.getValue() instanceof List) {
+            xw.printElementStartClose(false);
+            List values = (List) this.getValue();
+            for (Iterator vi = values.iterator(); vi.hasNext();) {
+                xw.println(vi.next());
+            }
+            xw.printElementEnd("property");
+        } else if (this.getValue() != null) {
+            xw.printAttribute("value", String.valueOf(this.getValue()));
+            xw.printElementStartClose(true);
+        }
+
+    }
+
+    void generateMetaTypeInfo(XMLWriter xw) {
+        if (!this.isPrivateProperty()) {
+            xw.printElementStart("AD", true);
+            xw.printAttribute("id", this.getName());
+            xw.printAttribute("type", this.getType());
+
+            if (this.getValue() instanceof List) {
+                List values = (List) this.getValue();
+                StringBuffer buf = new StringBuffer();
+                for (Iterator vi = values.iterator(); vi.hasNext();) {
+                    if (buf.length() > 0) buf.append(",");
+                    buf.append(vi.next());
+                }
+                xw.printAttribute("default", buf.toString());
+            } else if (this.getValue() != null) {
+                xw.printAttribute("default", String.valueOf(this.getValue()));
+            }
+
+            if (this.getLabel() != null) {
+                xw.printAttribute("name", this.getLabel());
+            } else {
+                // use the name as a localizable key by default
+                xw.printAttribute("name", "%" + this.getName() + ".name");
+            }
+
+            if (this.getDescription() != null) {
+                xw.printAttribute("description", this.getDescription());
+            } else {
+                // use the name as a localizable key by default
+                xw.printAttribute("description", "%" + this.getName() + ".description");
+            }
+
+            if (this.getCardinality() != 0) {
+                xw.printAttribute("cardinality", String.valueOf(this.getCardinality()));
+            }
+
+            if (this.getOptions() != null) {
+                xw.printElementStartClose(false);
+                for (Iterator oi=this.getOptions().entrySet().iterator(); oi.hasNext(); ) {
+                    Map.Entry entry = (Map.Entry) oi.next();
+                    xw.printElementStart("Option", true);
+                    xw.printAttribute("value", String.valueOf(entry.getKey()));
+                    xw.printAttribute("label", String.valueOf(entry.getValue()));
+                    xw.printElementStartClose(true);
+                }
+                xw.printElementEnd("AD");
+            } else {
+                xw.printElementStartClose(true);
+            }
+        }
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    protected void setName(String name) {
+        this.name = (name != null) ? name : "";
+
+        // default value for privateProperty field
+        this.privateProperty = name.equals(Constants.SERVICE_PID)
+            || name.equals(Constants.SERVICE_DESCRIPTION)
+            || name.equals(Constants.SERVICE_ID)
+            || name.equals(Constants.SERVICE_RANKING)
+            || name.equals(Constants.SERVICE_VENDOR)
+            || name.equals(ConfigurationAdmin.SERVICE_BUNDLELOCATION)
+            || name.equals(ConfigurationAdmin.SERVICE_FACTORYPID);
+    }
+
+    public String getLabel() {
+        return this.label;
+    }
+
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    public String getDescription() {
+        return this.description;
+    }
+
+    protected void setDescription(String description) {
+        this.description = description;
+    }
+
+    protected int getCardinality() {
+        return this.cardinality;
+    }
+
+    protected void setCardinality(String cardinality) {
+        if (cardinality == null) {
+            // simple scalar by default
+            this.cardinality = 0;
+        } else if ("-".equals(cardinality)) {
+            // unlimited vector
+            this.cardinality = Integer.MIN_VALUE;
+        } else if ("+".equals(cardinality)) {
+            // unlimited array
+            this.cardinality = Integer.MAX_VALUE;
+        } else {
+            try {
+                this.cardinality = Integer.parseInt(cardinality);
+            } catch (NumberFormatException nfe) {
+                // default to scalar in case of conversion problem
+                this.cardinality = 0;
+            }
+        }
+    }
+
+    protected void setCardinality(int cardinality) {
+        this.cardinality = cardinality;
+    }
+
+    protected void setPrivateProperty(boolean privateProperty) {
+        this.privateProperty = privateProperty;
+    }
+
+    protected boolean isPrivateProperty() {
+        return this.privateProperty;
+    }
+
+    public String getType() {
+        return this.type;
+    }
+
+    protected void setType(String type) {
+        if (!StringUtils.isEmpty(type)) {
+            this.type = type;
+        }
+    }
+
+    public Object getValue() {
+        return this.value;
+    }
+
+    protected void setValue(String value) {
+        this.value = (value == null) ? "" : value;
+    }
+
+    protected void setValues(Map valueMap) {
+        List values = new ArrayList();
+        for (Iterator vi = valueMap.entrySet().iterator(); vi.hasNext();) {
+            Map.Entry entry = (Map.Entry) vi.next();
+            String key = (String) entry.getKey();
+            if (key.startsWith("values")) {
+                values.add(entry.getValue());
+            }
+        }
+
+        if (!values.isEmpty()) {
+            this.value = values;
+
+            // assume array if set to scalar currently
+            if (this.cardinality == 0) {
+                this.cardinality = Integer.MAX_VALUE;
+            }
+        }
+    }
+
+    protected Map getOptions() {
+        return this.options;
+    }
+
+    protected void setOptions(Map options) {
+        this.options = options;
+    }
+
+    public int compareTo(Object obj) {
+        if (obj == this) {
+            return 0;
+        }
+
+        Property other = (Property) obj;
+        return this.getName().compareTo(other.getName());
+    }
+
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (obj instanceof Property) {
+            return this.getName().equals(((Property) obj).getName());
+        }
+
+        return false;
+    }
+
+    public int hashCode() {
+        return this.getName().hashCode();
+    }
+}

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Property.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Property.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Reference.java
URL: http://svn.apache.org/viewvc/felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Reference.java?view=auto&rev=562420
==============================================================================
--- felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Reference.java (added)
+++ felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Reference.java Fri Aug  3 05:07:45 2007
@@ -0,0 +1,252 @@
+/*
+ * 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.felix.sandbox.scrplugin;
+
+import org.apache.felix.sandbox.scrplugin.tags.JavaClassDescription;
+import org.apache.felix.sandbox.scrplugin.tags.JavaMethod;
+import org.apache.felix.sandbox.scrplugin.tags.JavaTag;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * Model: scr reference
+ */
+public class Reference extends AbstractDescriptorElement implements Comparable {
+
+    private String name = "";
+
+    private String interfaceName;
+
+    private String cardinality;
+
+    private String policy;
+
+    private String target;
+
+    private String bind = "bind";
+
+    private String unbind = "unbind";
+
+    Reference(Log log, JavaTag tag) {
+        super(log, tag);
+    }
+
+    boolean validate(/* JavaClass javaClass */)
+    throws MojoExecutionException {
+        boolean valid = true;
+
+        // validate name
+        if (StringUtils.isEmpty(this.name)) {
+            this.log("Reference has no name");
+            valid = false;
+        }
+
+        // validate interface
+        if (StringUtils.isEmpty(this.interfaceName)) {
+            this.log("Missing interface name");
+            valid = false;
+        }
+
+        // validate cardinality
+        if (this.cardinality == null) {
+            this.cardinality = "1..1";
+        } else if (!"0..1".equals(this.cardinality) && !"1..1".equals(this.cardinality)
+            && !"0..n".equals(this.cardinality) && !"1..n".equals(this.cardinality)) {
+            this.log("Invalid Cardinality specification " + this.cardinality);
+            valid = false;
+        }
+
+        // validate policy
+        if (this.policy == null) {
+            this.policy = "static";
+        } else if (!"static".equals(this.policy) && !"dynamic".equals(this.policy)) {
+            this.log("Invalid Policy specification " + this.policy);
+            valid = false;
+        }
+
+        // validate bind and unbind methods
+        JavaClassDescription javaClass = this.tag.getJavaClassDescription();
+        if (javaClass != null) {
+            this.bind = this.validateMethod(javaClass, this.bind);
+            this.unbind = this.validateMethod(javaClass, this.unbind);
+            valid = this.bind != null && this.unbind != null;
+        } else {
+            this.log("Cannot find Java class to which the reference belongs");
+            valid = false;
+        }
+
+        return valid;
+    }
+
+    private String validateMethod(JavaClassDescription javaClass, String methodName)
+    throws MojoExecutionException {
+
+        JavaMethod method = this.findMethod(javaClass, methodName);
+
+        if (method == null) {
+            this.log("Missing method " + methodName + " for reference " + this.getName());
+            return null;
+        }
+
+        if (method.isPublic()) {
+            this.warn("Method " + method.getName() + " should be declared protected");
+        } else if (!method.isProtected()) {
+            this.log("Method " + method.getName() + " has wrong qualifier, public or protected required");
+            return null;
+        }
+
+        return method.getName();
+    }
+
+    JavaMethod findMethod(JavaClassDescription javaClass, String methodName)
+    throws MojoExecutionException {
+
+        String[] sig = new String[]{ this.getInterfaceName() };
+        String[] sig2 = new String[]{ "org.osgi.framework.ServiceReference" };
+
+        // service interface or ServiceReference first
+        String realMethodName = methodName;
+        JavaMethod method = javaClass.getMethodBySignature(realMethodName, sig);
+        if (method == null) {
+            method = javaClass.getMethodBySignature(realMethodName, sig2);
+        }
+
+        // append reference name with service interface and ServiceReference
+        if (method == null) {
+            realMethodName = methodName + Character.toUpperCase(this.name.charAt(0))
+            + this.name.substring(1);
+
+            method = javaClass.getMethodBySignature(realMethodName, sig);
+        }
+        if (method == null) {
+            method = javaClass.getMethodBySignature(realMethodName, sig2);
+        }
+
+        // append type name with service interface and ServiceReference
+        if (method == null) {
+            int lastDot = this.getInterfaceName().lastIndexOf('.');
+            realMethodName = methodName
+                + this.getInterfaceName().substring(lastDot + 1);
+            method = javaClass.getMethodBySignature(realMethodName, sig);
+        }
+        if (method == null) {
+            method = javaClass.getMethodBySignature(realMethodName, sig2);
+        }
+
+        return method;
+    }
+
+    void generate(XMLWriter xw) {
+        xw.printElementStart("reference", true);
+        xw.printAttribute("name", this.getName());
+        xw.printAttribute("interface", this.interfaceName);
+        xw.printAttribute("target", this.getTarget());
+        xw.printAttribute("cardinality", this.getCardinality());
+        xw.printAttribute("policy", this.getPolicy());
+        xw.printAttribute("bind", this.getBind());
+        xw.printAttribute("unbind", this.getUnbind());
+        xw.printElementStartClose(true);
+    }
+
+    public String getBind() {
+        return this.bind;
+    }
+
+    protected void setBind(String bind) {
+        if (bind != null) {
+            this.bind = bind;
+        }
+    }
+
+    public String getCardinality() {
+        return this.cardinality;
+    }
+
+    protected void setCardinality(String cardinality) {
+        this.cardinality = cardinality;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    protected void setName(String name) {
+        this.name = (name != null) ? name : "";
+    }
+
+    public String getInterfaceName() {
+        return this.interfaceName;
+    }
+
+    protected void setInterface(String interfaceName) {
+        this.interfaceName = interfaceName;
+    }
+
+    public String getPolicy() {
+        return this.policy;
+    }
+
+    protected void setPolicy(String policy) {
+        this.policy = policy;
+    }
+
+    public String getTarget() {
+        return this.target;
+    }
+
+    protected void setTarget(String target) {
+        this.target = target;
+    }
+
+    public String getUnbind() {
+        return this.unbind;
+    }
+
+    protected void setUnbind(String unbind) {
+        if (unbind != null) {
+            this.unbind = unbind;
+        }
+    }
+
+    public int compareTo(Object obj) {
+        if (obj == this) {
+            return 0;
+        }
+
+        Reference other = (Reference) obj;
+        return this.getName().compareTo(other.getName());
+    }
+
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (obj instanceof Reference) {
+            return this.getName().equals(((Reference) obj).getName());
+        }
+
+        return false;
+    }
+
+    public int hashCode() {
+        return this.getName().hashCode();
+    }
+}

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Reference.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Reference.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/SCRDescriptor.java
URL: http://svn.apache.org/viewvc/felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/SCRDescriptor.java?view=auto&rev=562420
==============================================================================
--- felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/SCRDescriptor.java (added)
+++ felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/SCRDescriptor.java Fri Aug  3 05:07:45 2007
@@ -0,0 +1,438 @@
+/*
+ * 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.felix.sandbox.scrplugin;
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.felix.sandbox.scrplugin.tags.JavaClassDescription;
+import org.apache.felix.sandbox.scrplugin.tags.JavaMethod;
+import org.apache.felix.sandbox.scrplugin.tags.JavaParameter;
+import org.apache.felix.sandbox.scrplugin.tags.JavaTag;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+
+/**
+ * Model: scr base descriptor
+ */
+public class SCRDescriptor extends AbstractDescriptorElement {
+
+    public static final String COMPONENT = "scr.component";
+
+    public static final String COMPONENT_NAME = "name";
+
+    public static final String COMPONENT_LABEL = "label";
+
+    public static final String COMPONENT_DESCRIPTION = "description";
+
+    public static final String COMPONENT_ENABLED = "enabled";
+
+    public static final String COMPONENT_FACTORY = "factory";
+
+    public static final String COMPONENT_IMMEDIATE = "immediate";
+
+    public static final String COMPONENT_INHERIT = "inherit";
+
+    public static final String COMPONENT_METATYPE = "metatype";
+
+    public static final String COMPONENT_ABSTRACT = "abstract";
+
+    public static final String PROPERTY = "scr.property";
+
+    public static final String PROPERTY_NAME = "name";
+
+    public static final String PROPERTY_LABEL = "label";
+
+    public static final String PROPERTY_DESCRIPTION = "description";
+
+    public static final String PROPERTY_VALUE = "value";
+
+    public static final String PROPERTY_TYPE = "type";
+
+    public static final String PROPERTY_CARDINALITY = "cardinality";
+
+    public static final String PROPERTY_PRIVATE = "private";
+
+    public static final String PROPERTY_OPTIONS = "options";
+
+    public static final String SERVICE = "scr.service";
+
+    public static final String SERVICE_INTERFACE = "interface";
+
+    public static final String SERVICE_FACTORY = "servicefactory";
+
+    public static final String REFERENCE = "scr.reference";
+
+    public static final String REFERENCE_NAME = "name";
+
+    public static final String REFERENCE_INTERFACE = "interface";
+
+    public static final String REFERENCE_CARDINALITY = "cardinality";
+
+    public static final String REFERENCE_POLICY = "policy";
+
+    public static final String REFERENCE_TARGET = "target";
+
+    public static final String REFERENCE_BIND = "bind";
+
+    public static final String REFERENCE_UNDBIND = "unbind";
+
+    private String name;
+
+    private String label;
+
+    private String description;
+
+    private boolean enabled;
+
+    private String factory;
+
+    private boolean immediate;
+
+    private String implClass;
+
+    private boolean serviceFactory;
+
+    private boolean hasMetaType;
+
+    private boolean isAbstract;
+
+    // map of properties
+    private Set properties = new TreeSet();
+
+    // list of service interfaces
+    private Set services = new TreeSet();
+
+    // list of service references
+    private Set references = new TreeSet();
+
+    SCRDescriptor(Log log, JavaTag tag) {
+        super(log, tag);
+
+        // whether metatype information is to generated for the component
+        String metaType = tag.getNamedParameter(COMPONENT_METATYPE);
+        this.hasMetaType = metaType == null || "yes".equalsIgnoreCase(metaType)
+            || "true".equalsIgnoreCase(metaType);
+        // check if this is an abstract definition
+        String abstractType = tag.getNamedParameter(COMPONENT_ABSTRACT);
+        this.isAbstract = (abstractType == null ? false : "yes".equalsIgnoreCase(abstractType) || "true".equalsIgnoreCase(abstractType));
+    }
+
+    boolean isAbstract() {
+        return this.isAbstract;
+    }
+
+    // validates the descriptor and returns an array of issues or null
+    boolean validate() throws MojoExecutionException {
+
+        JavaClassDescription javaClass = this.tag.getJavaClassDescription();
+        if (javaClass == null) {
+            this.log("Tag not declared in a Java Class");
+            return false;
+        }
+
+        boolean valid = true;
+
+        // if the service is abstract, we do not validate everything
+        if ( !this.isAbstract ) {
+            // ensure non-abstract, public class
+            if (!javaClass.isPublic()) {
+                this.log("Class must be public");
+                valid = false;
+            }
+            if (javaClass.isAbstract() || javaClass.isInterface()) {
+                this.log("Class must be concrete class (not abstract or interface)");
+                valid = false;
+            }
+
+            // check activate and deactivate methods
+            this.checkActivationMethod(javaClass, "activate");
+            this.checkActivationMethod(javaClass, "deactivate");
+
+            // ensure public default constructor
+            boolean constructorFound = true;
+            JavaMethod[] methods = javaClass.getMethods();
+            for (int i = 0; methods != null && i < methods.length; i++) {
+                if (methods[i].isConstructor()) {
+                    // if public default, succeed
+                    if (methods[i].isPublic()
+                        && (methods[i].getParameters() == null || methods[i].getParameters().length == 0)) {
+                        constructorFound = true;
+                        break;
+                    }
+
+                    // non-public/non-default constructor found, must have explicit
+                    constructorFound = false;
+                }
+            }
+            if (!constructorFound) {
+                this.log("Class must have public default constructor");
+                valid = false;
+            }
+
+            // verify properties
+            for (Iterator pi = this.getProperties(); pi.hasNext();) {
+                Property prop = (Property) pi.next();
+                valid &= prop.validate();
+            }
+
+            // verify services
+            for (Iterator si = this.getServices(); si.hasNext();) {
+                Service service = (Service) si.next();
+                valid &= service.validate();
+            }
+
+            // serviceFactory must not be true for immediate of component factory
+            if (this.isServiceFactory() && this.isImmediate() && this.getFactory() != null) {
+                this.log("Component must not be a ServiceFactory, if immediate and/or component factory");
+                valid = false;
+            }
+
+            // verify references
+            for (Iterator ri = this.getReferences(); ri.hasNext();) {
+                Reference ref = (Reference) ri.next();
+                valid &= ref.validate();
+            }
+        }
+        return valid;
+    }
+
+    private void checkActivationMethod(JavaClassDescription javaClass, String methodName) {
+        JavaMethod[] methods = javaClass.getMethods();
+        JavaMethod activation = null;
+        for (int i=0; i < methods.length; i++) {
+            // ignore method not matching the name
+            if (!methodName.equals(methods[i].getName())) {
+                continue;
+            }
+
+            // if the method has the correct parameter type, check protected
+            JavaParameter[] params = methods[i].getParameters();
+            if (params == null || params.length != 1) {
+                continue;
+            }
+
+            // this might be considered, if it is an overload, drop out of check
+            if (activation != null) {
+                return;
+            }
+
+            // consider this method for further checks
+            activation = methods[i];
+        }
+
+        // no activation method found
+        if (activation == null) {
+            return;
+        }
+
+        // check protected
+        if (activation.isPublic()) {
+            this.warn("Activation method " + activation.getName() + " should be declared protected");
+        } else if (!activation.isProtected()) {
+            this.warn("Activation method " + activation.getName() + " has wrong qualifier, public or protected required");
+        }
+
+        // check paramter (we know there is exactly one)
+        JavaParameter param = activation.getParameters()[0];
+        if (!"org.osgi.service.component.ComponentContext".equals(param.getType())) {
+            this.warn("Activation method " + methodName + " has wrong argument type " + param.getType());
+        }
+    }
+
+    void generate(XMLWriter xw) {
+        xw.printElementStart("component", true);
+        xw.printAttribute("name", this.getName());
+        if (!this.isEnabled())
+            xw.printAttribute("enabled", String.valueOf(this.isEnabled()));
+        if (this.getFactory() != null) xw.printAttribute("factory", this.getFactory());
+        xw.printAttribute("immediate", String.valueOf(this.isImmediate()));
+        xw.printElementStartClose(false);
+
+        xw.indent();
+
+        xw.printElementStart("implementation", true);
+        xw.printAttribute("class", this.getImplClass());
+        xw.printElementStartClose(true);
+
+        // properties
+        for (Iterator pi = this.getProperties(); pi.hasNext();) {
+            ((Property) pi.next()).generate(xw);
+        }
+
+        // services
+        Iterator si = this.getServices();
+        if (si.hasNext()) {
+            xw.printElementStart("service", this.isServiceFactory());
+            if (this.isServiceFactory()) {
+                xw.printAttribute("servicefactory", "true");
+                xw.printElementStartClose(false);
+            }
+            xw.indent();
+            while (si.hasNext()) {
+                ((Service) si.next()).generate(xw);
+            }
+            xw.outdent();
+            xw.printElementEnd("service");
+        }
+
+        // references
+        for (Iterator ri = this.getReferences(); ri.hasNext();) {
+            ((Reference) ri.next()).generate(xw);
+        }
+
+        xw.outdent();
+        xw.printElementEnd("component");
+    }
+
+    void generateMetaTypeInfo(XMLWriter xw) {
+
+        // if there is no metatype, we return early
+        if (!this.hasMetaType) {
+            return;
+        }
+
+        xw.printElementStart("OCD", true);
+        xw.printAttribute("id", this.getName());
+
+        if (this.getLabel() != null) {
+            xw.printAttribute("name", this.getLabel());
+        } else {
+            // use the name as a localizable key by default
+            xw.printAttribute("name", "%" + this.getName() + ".name");
+        }
+
+        if (this.getDescription() != null) {
+            xw.printAttribute("description", this.getDescription());
+        } else {
+            // use the name as a localizable key by default
+            xw.printAttribute("description", "%" + this.getName() + ".description");
+        }
+
+        xw.printElementStartClose(false);
+
+        // properties
+        for (Iterator pi = this.getProperties(); pi.hasNext();) {
+            ((Property) pi.next()).generateMetaTypeInfo(xw);
+        }
+
+        xw.printElementEnd("OCD");
+
+        xw.printElementStart("Designate", true);
+        xw.printAttribute("pid", this.getName());
+        xw.printElementStartClose(false);
+
+        xw.printElementStart("Object", true);
+        xw.printAttribute("ocdref", this.getName());
+        xw.printElementStartClose(true);
+
+        xw.printElementEnd("Designate");
+    }
+
+    // ---------- Setters and Getters for the properties -----------------------
+
+    public boolean isEnabled() {
+        return this.enabled;
+    }
+
+    void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    public String getFactory() {
+        return this.factory;
+    }
+
+    void setFactory(String factory) {
+        this.factory = factory;
+    }
+
+    public boolean isImmediate() {
+        return this.immediate;
+    }
+
+    void setImmediate(boolean immediate) {
+        this.immediate = immediate;
+    }
+
+    public String getImplClass() {
+        return this.implClass;
+    }
+
+    void setImplClass(String implClass) {
+        this.implClass = implClass;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    void setName(String name) {
+        this.name = name;
+    }
+
+    String getLabel() {
+        return this.label;
+    }
+
+    void setLabel(String label) {
+        this.label = label;
+    }
+
+    String getDescription() {
+        return this.description;
+    }
+
+    void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Iterator getProperties() {
+        return this.properties.iterator();
+    }
+
+    void addProperty(Property property) {
+        this.properties.add(property);
+    }
+
+    public Iterator getReferences() {
+        return this.references.iterator();
+    }
+
+    void addReference(Reference reference) {
+        this.references.add(reference);
+    }
+
+    public boolean isServiceFactory() {
+        return this.serviceFactory;
+    }
+
+    void setServiceFactory(boolean serviceFactory) {
+        this.serviceFactory = serviceFactory;
+    }
+
+    public Iterator getServices() {
+        return this.services.iterator();
+    }
+
+    void addService(Service service) {
+        this.services.add(service);
+    }
+}

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/SCRDescriptor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/SCRDescriptor.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/SCRDescriptorMojo.java
URL: http://svn.apache.org/viewvc/felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/SCRDescriptorMojo.java?view=auto&rev=562420
==============================================================================
--- felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/SCRDescriptorMojo.java (added)
+++ felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/SCRDescriptorMojo.java Fri Aug  3 05:07:45 2007
@@ -0,0 +1,385 @@
+/*
+ * 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.felix.sandbox.scrplugin;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.sandbox.scrplugin.tags.JavaClassDescription;
+import org.apache.felix.sandbox.scrplugin.tags.JavaClassDescriptorManager;
+import org.apache.felix.sandbox.scrplugin.tags.JavaField;
+import org.apache.felix.sandbox.scrplugin.tags.JavaTag;
+import org.apache.maven.model.Resource;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * The <code>SCRDescriptorMojo</code>
+ * generates a service descriptor file based on annotations found in the sources.
+ *
+ * @goal scr
+ * @phase generate-resources
+ * @description Build Service Descriptors from Java Source
+ * @requiresDependencyResolution compile
+ */
+public class SCRDescriptorMojo extends AbstractMojo {
+
+    /**
+     * @parameter expression="${project.build.directory}/scr-plugin-generated"
+     * @required
+     * @readonly
+     */
+    private File outputDirectory;
+
+    /**
+     * The Maven project.
+     *
+     * @parameter expression="${project}"
+     * @required
+     * @readonly
+     */
+    private MavenProject project;
+
+    /**
+     * Name of the generated descriptor.
+     *
+     * @parameter expression="${scr.descriptor.name}" default-value="serviceComponents.xml"
+     */
+    private String finalName;
+
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        this.getLog().debug("Starting SCRDescriptorMojo....");
+
+        boolean hasFailures = false;
+
+        JavaClassDescriptorManager jManager = new JavaClassDescriptorManager(this.getLog(),
+                                                                             this.project);
+        // iterate through all source classes and check for component tag
+        final List descriptors = new ArrayList();
+        final List abstractDescriptors = new ArrayList();
+        final JavaClassDescription[] javaSources = jManager.getSourceDescriptions();
+
+        for (int i = 0; i < javaSources.length; i++) {
+            this.getLog().debug("Testing source " + javaSources[i].getName());
+            final JavaTag tag = javaSources[i].getTagByName(SCRDescriptor.COMPONENT);
+            if (tag != null) {
+                this.getLog().debug("Processing service class " + javaSources[i].getName());
+                final SCRDescriptor descriptor = this.createSCRDescriptor(javaSources[i]);
+                if (descriptor != null) {
+                    if ( descriptor.isAbstract() ) {
+                        this.getLog().debug("Adding descriptor " + descriptor);
+                        abstractDescriptors.add(descriptor);
+                    } else {
+                        this.getLog().debug("Adding abstract descriptor " + descriptor);
+                        descriptors.add(descriptor);
+                    }
+                } else {
+                    hasFailures = true;
+                }
+            }
+        }
+
+        // after checking all classes, throw if there were any failures
+        if (hasFailures) {
+            throw new MojoFailureException("SCR Descriptor parsing had failures (see log)");
+        }
+
+        jManager.writeAbstractDescriptorsFile(abstractDescriptors, this.outputDirectory);
+
+        // terminate if there is nothing to write
+        if (descriptors.isEmpty()) {
+            this.getLog().info("No SCR Descriptors found in project");
+            return;
+        }
+
+        // finally the descriptors have to be written ....
+        if (StringUtils.isEmpty(this.finalName)) {
+            this.getLog().error("Descriptor file name must not be empty");
+            return;
+        }
+
+        File descriptorFile = new File(new File(this.outputDirectory, "OSGI-INF"), this.finalName);
+        descriptorFile.getParentFile().mkdirs(); // ensure parent dir
+
+        this.getLog().info("Generating " + descriptors.size()
+                + " Service Component Descriptors to " + descriptorFile);
+
+        FileOutputStream descriptorStream = null;
+        XMLWriter xw = null;
+        try {
+            descriptorStream = new FileOutputStream(descriptorFile);
+            xw = new XMLWriter(descriptorStream);
+
+            for (Iterator di=descriptors.iterator(); di.hasNext(); ) {
+                SCRDescriptor sd = (SCRDescriptor) di.next();
+                sd.generate(xw);
+            }
+
+        } catch (IOException ioe) {
+            hasFailures = true;
+            this.getLog().error("Cannot write descriptor to " + descriptorFile, ioe);
+            throw new MojoFailureException("Failed to write descriptor to " + descriptorFile);
+        } finally {
+            IOUtil.close(xw);
+            IOUtil.close(descriptorStream);
+
+            // remove the descriptor file in case of write failure
+            if (hasFailures) {
+                descriptorFile.delete();
+            }
+        }
+
+        // create metatype information
+        File mtFile = new File(this.outputDirectory, "OSGI-INF" + File.separator + "metatype" + File.separator + "metatype.xml");
+        mtFile.getParentFile().mkdirs();
+
+        xw = null;
+        descriptorStream = null;
+        try {
+            descriptorStream = new FileOutputStream(mtFile);
+            xw = new XMLWriter(descriptorStream);
+
+            xw.printElementStart("MetaData", true);
+            xw.printAttribute("localization", "metatype");
+            xw.printElementStartClose(false);
+
+            for (Iterator di=descriptors.iterator(); di.hasNext(); ) {
+                SCRDescriptor sd = (SCRDescriptor) di.next();
+                sd.generateMetaTypeInfo(xw);
+            }
+
+            xw.printElementEnd("MetaData");
+
+        } catch (IOException ioe) {
+            this.getLog().error("Cannot write meta type descriptor", ioe);
+            throw new MojoFailureException("Failed to write meta type descriptor");
+        } finally {
+            IOUtil.close(xw);
+            IOUtil.close(descriptorStream);
+        }
+
+        // now add the descriptor file to the maven resources
+        final String ourRsrcPath = this.outputDirectory.getAbsolutePath();
+        boolean found = false;
+        final Iterator rsrcIterator = this.project.getResources().iterator();
+        while ( !found && rsrcIterator.hasNext() ) {
+            final Resource rsrc = (Resource)rsrcIterator.next();
+            found = rsrc.getDirectory().equals(ourRsrcPath);
+        }
+        if ( !found ) {
+            final Resource resource = new Resource();
+            resource.setDirectory(this.outputDirectory.getAbsolutePath());
+            this.project.addResource(resource);
+        }
+        // and set include accordingly
+        this.project.getProperties().setProperty("Service-Component", "OSGI-INF/" + this.finalName);
+    }
+
+    private SCRDescriptor createSCRDescriptor(JavaClassDescription description)
+    throws MojoExecutionException {
+
+        final JavaTag component = description.getTagByName(SCRDescriptor.COMPONENT);
+        final SCRDescriptor sd = new SCRDescriptor(this.getLog(), component);
+        sd.setImplClass(description.getName());
+
+        boolean inherited = this.getBoolean(component, SCRDescriptor.COMPONENT_INHERIT, false);
+
+        this.doComponent(component, sd);
+
+        boolean serviceFactory = this.doServices(description.getTagsByName(SCRDescriptor.SERVICE, inherited), sd, description);
+        sd.setServiceFactory(serviceFactory);
+
+        this.doProperties(description.getTagsByName(SCRDescriptor.PROPERTY, inherited), sd);
+
+        this.doReferences(description.getTagsByName(SCRDescriptor.REFERENCE, inherited), sd);
+
+        do {
+            JavaField[] fields = description.getFields();
+            for (int i=0; fields != null && i < fields.length; i++) {
+                JavaTag tag = fields[i].getTagByName(SCRDescriptor.REFERENCE);
+                if (tag != null) {
+                    this.doReference(tag, fields[i].getName(), sd);
+                }
+
+                tag = fields[i].getTagByName(SCRDescriptor.PROPERTY);
+                if (tag != null) {
+                    this.doProperty(tag, fields[i].getInitializationExpression(), sd);
+                }
+            }
+
+            description = description.getSuperClass();
+        } while (inherited && description != null);
+
+        // return nothing if validation fails
+        return sd.validate() ? sd : null;
+    }
+
+    private void doComponent(JavaTag comp, SCRDescriptor sd) {
+        String name = comp.getNamedParameter(SCRDescriptor.COMPONENT_NAME);
+        sd.setName(StringUtils.isEmpty(name) ? sd.getImplClass() : name);
+
+        sd.setEnabled(this.getBoolean(comp, SCRDescriptor.COMPONENT_ENABLED, true));
+        sd.setFactory(comp.getNamedParameter(SCRDescriptor.COMPONENT_FACTORY));
+        sd.setImmediate(this.getBoolean(comp, SCRDescriptor.COMPONENT_IMMEDIATE,
+            true));
+
+        sd.setLabel(comp.getNamedParameter(SCRDescriptor.COMPONENT_LABEL));
+        sd.setDescription(comp.getNamedParameter(SCRDescriptor.COMPONENT_DESCRIPTION));
+    }
+
+    private boolean doServices(JavaTag[] services, SCRDescriptor sd, JavaClassDescription description)
+    throws MojoExecutionException {
+        // no services, hence certainly no service factory
+        if (services == null || services.length == 0) {
+            return false;
+        }
+
+        boolean serviceFactory = false;
+        for (int i=0; i < services.length; i++) {
+            String name = services[i].getNamedParameter(SCRDescriptor.SERVICE_INTERFACE);
+            if (StringUtils.isEmpty(name)) {
+
+                while (description != null) {
+                    JavaClassDescription[] interfaces = description.getImplementedInterfaces();
+                    for (int j=0; interfaces != null && j < interfaces.length; j++) {
+                        Service service = new Service(this.getLog(), services[i]);
+                        service.setInterfaceName(interfaces[j].getName());
+                        sd.addService(service);
+                    }
+
+                    // try super class
+                    description = description.getSuperClass();
+                }
+            } else {
+                Service service = new Service(this.getLog(), services[i]);
+                service.setInterfaceName(name);
+                sd.addService(service);
+            }
+
+            serviceFactory |= this.getBoolean(services[i], SCRDescriptor.SERVICE_FACTORY, false);
+        }
+
+        return serviceFactory;
+    }
+
+    private void doProperties(JavaTag[] properties, SCRDescriptor sd) {
+        if (properties == null || properties.length == 0) {
+            return;
+        }
+
+        for (int i=0; i < properties.length; i++) {
+            this.doProperty(properties[i], null, sd);
+        }
+    }
+
+    private void doProperty(JavaTag property, String defaultName, SCRDescriptor sd) {
+        String name = property.getNamedParameter(SCRDescriptor.PROPERTY_NAME);
+        if (StringUtils.isEmpty(name) && defaultName!= null) {
+            name = defaultName.trim();
+            if (name.startsWith("\"")) name = name.substring(1);
+            if (name.endsWith("\"")) name = name.substring(0, name.length()-1);
+        }
+
+        if (!StringUtils.isEmpty(name)) {
+            Property prop = new Property(this.getLog(), property);
+            prop.setName(name);
+            prop.setLabel(property.getNamedParameter(SCRDescriptor.PROPERTY_LABEL));
+            prop.setDescription(property.getNamedParameter(SCRDescriptor.PROPERTY_DESCRIPTION));
+            prop.setValue(property.getNamedParameter(SCRDescriptor.PROPERTY_VALUE));
+            prop.setType(property.getNamedParameter(SCRDescriptor.PROPERTY_TYPE));
+            prop.setPrivateProperty(this.getBoolean(property,
+                SCRDescriptor.PROPERTY_PRIVATE, prop.isPrivateProperty()));
+
+            // set optional multivalues, cardinailty might be overwritten by setValues !!
+            prop.setCardinality(property.getNamedParameter(SCRDescriptor.PROPERTY_CARDINALITY));
+            prop.setValues(property.getNamedParameterMap());
+
+            // check options
+            String[] parameters = property.getParameters();
+            Map options = null;
+            for (int j=0; j < parameters.length; j++) {
+                if (SCRDescriptor.PROPERTY_OPTIONS.equals(parameters[j])) {
+                    options = new LinkedHashMap();
+                } else if (options != null) {
+                    String optionLabel = parameters[j];
+                    String optionValue = (j < parameters.length-2) ? parameters[j+2] : null;
+                    if (optionValue != null) {
+                        options.put(optionLabel, optionValue);
+                    }
+                    j += 2;
+                }
+            }
+            prop.setOptions(options);
+
+            sd.addProperty(prop);
+        }
+    }
+
+    private void doReferences(JavaTag[] references, SCRDescriptor sd) {
+        if (references == null || references.length == 0) {
+            return;
+        }
+
+        for (int i=0; i < references.length; i++) {
+            this.doReference(references[i], null, sd);
+        }
+    }
+
+    private void doReference(JavaTag reference, String defaultName, SCRDescriptor sd) {
+        String name = reference.getNamedParameter(SCRDescriptor.REFERENCE_NAME);
+        if (StringUtils.isEmpty(name)) {
+            name = defaultName;
+        }
+
+        // ensure interface
+        String type = reference.getNamedParameter(SCRDescriptor.REFERENCE_INTERFACE);
+        if (StringUtils.isEmpty(type)) {
+            if ( reference.getField() != null ) {
+                type = reference.getField().getType();
+            }
+        }
+
+        if (!StringUtils.isEmpty(name)) {
+            Reference ref = new Reference(this.getLog(), reference);
+            ref.setName(name);
+            ref.setInterface(type);
+            ref.setCardinality(reference.getNamedParameter(SCRDescriptor.REFERENCE_CARDINALITY));
+            ref.setPolicy(reference.getNamedParameter(SCRDescriptor.REFERENCE_POLICY));
+            ref.setTarget(reference.getNamedParameter(SCRDescriptor.REFERENCE_TARGET));
+            ref.setBind(reference.getNamedParameter(SCRDescriptor.REFERENCE_BIND));
+            ref.setUnbind(reference.getNamedParameter(SCRDescriptor.REFERENCE_UNDBIND));
+            sd.addReference(ref);
+        }
+    }
+
+    private boolean getBoolean(JavaTag tag, String name, boolean defaultValue) {
+        String value = tag.getNamedParameter(name);
+        return (value == null) ? defaultValue : Boolean.valueOf(value).booleanValue();
+    }
+}

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/SCRDescriptorMojo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/SCRDescriptorMojo.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Service.java
URL: http://svn.apache.org/viewvc/felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Service.java?view=auto&rev=562420
==============================================================================
--- felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Service.java (added)
+++ felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Service.java Fri Aug  3 05:07:45 2007
@@ -0,0 +1,96 @@
+/*
+ * 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.felix.sandbox.scrplugin;
+
+import org.apache.felix.sandbox.scrplugin.tags.JavaClassDescription;
+import org.apache.felix.sandbox.scrplugin.tags.JavaTag;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+
+/**
+ * The <code>Service</code>
+ *
+ */
+public class Service extends AbstractDescriptorElement implements Comparable {
+
+    private String interfaceName = "";
+
+    /**
+     * @param log
+     * @param tag
+     */
+    public Service(Log log, JavaTag tag) {
+        super(log, tag);
+    }
+
+    void generate(XMLWriter xmlWriter) {
+        xmlWriter.printElementStart("provide", true);
+        xmlWriter.printAttribute("interface", this.getInterfaceName());
+        xmlWriter.printElementStartClose(true);
+    }
+
+    boolean validate() throws MojoExecutionException {
+        JavaClassDescription javaClass = this.tag.getJavaClassDescription();
+        if (javaClass == null) {
+            this.log("Must be declared in a Java class");
+            return false;
+        }
+
+        if ( javaClass.isA(this.getInterfaceName()) ) {
+            return true;
+        }
+
+        // interface not implemented
+        this.log("Class must implement provided interface " + this.getInterfaceName());
+        return false;
+    }
+
+    public String getInterfaceName() {
+        return this.interfaceName;
+    }
+
+    void setInterfaceName(String interfaceName) {
+        this.interfaceName = (interfaceName != null) ? interfaceName : "";
+    }
+
+    public int compareTo(Object obj) {
+        if (obj == this) {
+            return 0;
+        }
+
+        Service other = (Service) obj;
+        return this.getInterfaceName().compareTo(other.getInterfaceName());
+    }
+
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (obj instanceof Service) {
+            return this.getInterfaceName().equals(((Service) obj).getInterfaceName());
+        }
+
+        return false;
+    }
+
+    public int hashCode() {
+        return this.getInterfaceName().hashCode();
+    }
+}

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Service.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/Service.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/XMLWriter.java
URL: http://svn.apache.org/viewvc/felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/XMLWriter.java?view=auto&rev=562420
==============================================================================
--- felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/XMLWriter.java (added)
+++ felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/XMLWriter.java Fri Aug  3 05:07:45 2007
@@ -0,0 +1,83 @@
+/*
+ * 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.felix.sandbox.scrplugin;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * Simple xml writer.
+ */
+public class XMLWriter extends PrintWriter {
+
+    String indent = "";
+
+    XMLWriter(OutputStream descriptorStream) throws IOException {
+        super(new OutputStreamWriter(descriptorStream, "UTF-8"));
+
+        this.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+    }
+
+    void indent() {
+        this.indent += "  ";
+    }
+
+    void outdent() {
+        if (this.indent.length() >= 2) {
+            this.indent = this.indent.substring(2);
+        }
+    }
+
+    void printElementStart(String name, boolean hasAttributes) {
+        this.print(this.indent);
+        this.print("<");
+        this.print(name);
+        if (!hasAttributes) {
+            this.printElementStartClose(false);
+        }
+    }
+
+    void printElementStartClose(boolean isEmpty) {
+        if (isEmpty) {
+            this.print(" /");
+        }
+        this.println('>');
+    }
+
+    void printElementEnd(String name) {
+        this.print(this.indent);
+        this.print("</");
+        this.print(name);
+        this.println('>');
+    }
+
+    void printAttribute(String name, String value) {
+        if (!StringUtils.isEmpty(name) && value != null) {
+            this.print(' ');
+            this.print(name);
+            this.print("=\"");
+            this.print(value);
+            this.print('"');
+        }
+    }
+}

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/XMLWriter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/XMLWriter.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/JavaClassDescription.java
URL: http://svn.apache.org/viewvc/felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/JavaClassDescription.java?view=auto&rev=562420
==============================================================================
--- felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/JavaClassDescription.java (added)
+++ felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/JavaClassDescription.java Fri Aug  3 05:07:45 2007
@@ -0,0 +1,101 @@
+/*
+ * 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.felix.sandbox.scrplugin.tags;
+
+import org.apache.maven.plugin.MojoExecutionException;
+
+/**
+ * <code>JavaClassDescription.java</code>...
+ * Description of a java class
+ *
+ */
+public interface JavaClassDescription {
+
+    /**
+     * Get the java class tag with the name.
+     * @param name
+     * @return the tag or null.
+     */
+    JavaTag getTagByName(String name);
+
+    /**
+     * Get all class tags with this name.
+     * @param name
+     * @param inherited If true, parent classes are searched as well.
+     * @return An array of tags or the empty array.
+     * @throws MojoExecutionException
+     */
+    JavaTag[] getTagsByName(String name, boolean inherited)
+    throws MojoExecutionException;
+
+    /**
+     * Get the description for the parent class.
+     * @return
+     * @throws MojoExecutionException
+     */
+    JavaClassDescription getSuperClass() throws MojoExecutionException;
+
+    /**
+     * Get the name of the described class.
+     * @return
+     */
+    String getName();
+
+    JavaField[] getFields();
+
+    JavaClassDescription[] getImplementedInterfaces() throws MojoExecutionException;
+
+    /**
+     * Search for a method with the given signature.
+     * @param name
+     * @param parameters
+     * @return
+     * @throws MojoExecutionException
+     */
+    JavaMethod getMethodBySignature(String name, String[] parameters)
+    throws MojoExecutionException;
+
+    /**
+     * Is this class public?
+     * @return
+     */
+    boolean isPublic();
+
+    /**
+     * Is this class abstract?
+     * @return
+     */
+    boolean isAbstract();
+
+    /**
+     * Is this class an interface?
+     * @return
+     */
+    boolean isInterface();
+
+    JavaMethod[] getMethods();
+
+    /**
+     * Is this class of the type?
+     * @param type
+     * @return
+     * @throws MojoExecutionException
+     */
+    boolean isA(String type) throws MojoExecutionException;
+}

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/JavaClassDescription.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/sandbox/cziegeler/maven-scr-plugin/src/main/java/org/apache/felix/sandbox/scrplugin/tags/JavaClassDescription.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url



Mime
View raw message