Author: mrdon Date: Sun Mar 2 04:33:04 2008 New Revision: 632748 URL: http://svn.apache.org/viewvc?rev=632748&view=rev Log: Adding functional view bundle actions, proper shutdown, lots of small changes
Added: struts/sandbox/trunk/struts2-osgi-plugin/pom.xml Modified: struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/pom.xml struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/java/org/apache/struts2/osgi/admin/BundlesAction.java struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/resources/osgi/admin/viewBundle.vm struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/resources/osgi/admin/viewBundles.vm struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/resources/struts.xml struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundleAccessor.java struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundlePackageLoader.java struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DefaultBundleAccessor.java struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DelegatingObjectFactory.java struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java Modified: struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/pom.xml URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/pom.xml?rev=632748&r1=632747&r2=632748&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/pom.xml (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/pom.xml Sun Mar 2 04:33:04 2008 @@ -16,6 +16,10 @@ </dependencies> + <properties> + <jdkLevel>1.5</jdkLevel> + </properties> + <build> <plugins> @@ -34,5 +38,16 @@ </configuration> </plugin> </plugins> + <pluginManagement> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>1.5</source> + <target>1.5</target> + </configuration> + </plugin> + </plugins> + </pluginManagement> </build> </project> Modified: struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/java/org/apache/struts2/osgi/admin/BundlesAction.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/java/org/apache/struts2/osgi/admin/BundlesAction.java?rev=632748&r1=632747&r2=632748&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/java/org/apache/struts2/osgi/admin/BundlesAction.java (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/java/org/apache/struts2/osgi/admin/BundlesAction.java Sun Mar 2 04:33:04 2008 @@ -1,11 +1,23 @@ package org.apache.struts2.osgi.admin; import org.apache.struts2.dispatcher.DefaultActionSupport; +import org.apache.struts2.osgi.BundleAccessor; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleException; +import com.opensymphony.xwork2.inject.Inject; +import com.opensymphony.xwork2.config.entities.PackageConfig; +import com.opensymphony.xwork2.config.Configuration; + +import java.util.*; +import java.lang.reflect.Array; public class BundlesAction extends DefaultActionSupport { private String id; + private BundleAccessor bundleAccessor; + private Configuration configuration; + public String index() { return SUCCESS; } @@ -14,11 +26,80 @@ return SUCCESS; } + public String start() throws BundleException { + Bundle bundle = bundleAccessor.getBundles().get(id); + bundle.start(); + return view(); + } + + public String stop() throws BundleException { + Bundle bundle = bundleAccessor.getBundles().get(id); + bundle.stop(); + return view(); + } + + public String getId() { return id; } public void setId(String id) { this.id = id; + } + + public Bundle getBundle() { + return bundleAccessor.getBundles().get(id); + } + + @Inject + public void setBundleAccessor(BundleAccessor bundleAccessor) { + this.bundleAccessor = bundleAccessor; + } + + public List<PackageConfig> getPackages() { + List<PackageConfig> pkgs = new ArrayList<PackageConfig>(); + Bundle bundle = getBundle(); + for (String name : bundleAccessor.getPackagesByBundle(bundle)) { + pkgs.add(configuration.getPackageConfig(name)); + } + return pkgs; + } + + public Collection<Bundle> getBundles() { + return bundleAccessor.getBundles().values(); + } + + public String displayProperty(Object obj) { + if (obj.getClass().isArray()) { + return Arrays.asList((Object[])obj).toString(); + } else { + return obj.toString(); + } + } + + public String getBundleState(Bundle bundle) { + switch (bundle.getState()) { + case Bundle.ACTIVE : return "Active"; + case Bundle.INSTALLED : return "Installed"; + case Bundle.RESOLVED : return "Resolved"; + case Bundle.STARTING : return "Starting"; + case Bundle.STOPPING : return "Stopping"; + case Bundle.UNINSTALLED : return "Uninstalled"; + default : throw new IllegalStateException("Invalid state"); + } + } + + public boolean isAllowedAction(Bundle bundle, String val) { + if ("start".equals(val)) { + return bundle.getState() == Bundle.INSTALLED; + } else if ("stop".equals(val)) { + return bundle.getState() == Bundle.ACTIVE; + } + throw new IllegalArgumentException("Invalid state"); + } + + @Inject + public void setConfiguration(Configuration configuration) { + this.configuration = configuration; } } Modified: struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/resources/osgi/admin/viewBundle.vm URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/resources/osgi/admin/viewBundle.vm?rev=632748&r1=632747&r2=632748&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/resources/osgi/admin/viewBundle.vm (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/resources/osgi/admin/viewBundle.vm Sun Mar 2 04:33:04 2008 @@ -1 +1,92 @@ -This is a bundle view ${id} \ No newline at end of file +<html> +<body> +<table> + <tr> + <th>Id</th> + <td>$bundle.bundleId</td> + </tr> + <tr> + <th>Name</th> + <td>$bundle.symbolicName</td> + </tr> + <tr> + <th>Location</th> + <td>$bundle.location</td> + </tr> + <tr> + <th>State</th> + <td>$action.getBundleState($bundle)</td> + </tr> + <tr> + <th>Registered Services</th> + <td> + <ul> + #foreach ($service in $bundle.registeredServices) + <li> + #foreach ($key in $service.propertyKeys) + $key = $action.displayProperty($service.getProperty($key)) <br /> + #end + #if ($service.usingBundles.length > 0) + Used by: + <ul> + #foreach ($user in $service.usingBundles) + <li>$user.symbolicName</li> + #end + </ul> + #end + </li> + #end + </ul> + </td> + </tr> + <tr> + <th>Services in Use</th> + <td> + <ul> + #foreach ($service in $bundle.servicesInUse) + <li> + #foreach ($key in $service.propertyKeys) + $key = $action.displayProperty($service.getProperty($key)) <br /> + #end + #if ($service.usingBundles.length > 0) + Also used by: + <ul> + #foreach ($user in $service.usingBundles) + <li>$user.symbolicName</li> + #end + </ul> + #end + </li> + #end + </ul> + </td> + </tr> + <tr> + <th>Packages</th> + <td> + #foreach ($pkg in $packages) + <strong>$pkg.name</strong> + <ul> + #foreach ($name in $pkg.actionConfigs.keySet()) + <li>$name</li> + #end + </ul> + #end + </td> + </tr> + <tr> + <th>Actions</th> + <td> + #if ($action.isAllowedAction($bundle, "start")) + <a href="bundle_${bundle.symbolicName}!start.action">Start</a> + #end + + #if ($action.isAllowedAction($bundle, "stop")) + <a href="bundle_${bundle.symbolicName}!stop.action">Stop</a> + #end + </td> + </tr> + +</table> +</body> +</html> \ No newline at end of file Modified: struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/resources/osgi/admin/viewBundles.vm URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/resources/osgi/admin/viewBundles.vm?rev=632748&r1=632747&r2=632748&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/resources/osgi/admin/viewBundles.vm (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/resources/osgi/admin/viewBundles.vm Sun Mar 2 04:33:04 2008 @@ -1 +1,34 @@ -These are all bundles \ No newline at end of file +<html> +<head> + <title>OSGi Bundles</title> +</head> +<body> + +<table> + <thead> + <tr> + <th>Name</th> + <th>State</th> + <th>Actions</th> + </tr> + </thead> + <tbody> + #foreach ($bundle in $bundles) + <tr> + <td>$bundle.symbolicName</td> + <td>$action.getBundleState($bundle)</td> + <td> + #if ($action.isAllowedAction($bundle, "start")) + <a href="bundle_${bundle.symbolicName}!start.action">Start</a> + #end + + #if ($action.isAllowedAction($bundle, "stop")) + <a href="bundle_${bundle.symbolicName}!stop.action">Stop</a> + #end + </td> + </tr> + #end + </tbody> +</table> +</body> +</html> Modified: struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/resources/struts.xml URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/resources/struts.xml?rev=632748&r1=632747&r2=632748&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/resources/struts.xml (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/resources/struts.xml Sun Mar 2 04:33:04 2008 @@ -5,8 +5,8 @@ <struts> - <package name="bundle" namespace="/osgi/admin" extends="struts-default"> - <action name="bundles/*" class="org.apache.struts2.osgi.admin.BundlesAction" method="view"> + <package name="bundle-admin" namespace="/osgi/admin" extends="struts-default"> + <action name="bundle_*" class="org.apache.struts2.osgi.admin.BundlesAction" method="view"> <param name="id">{1}</param> <result type="velocity">viewBundle.vm</result> </action> @@ -14,8 +14,5 @@ <result type="velocity">viewBundles.vm</result> </action> </package> - <include file="example.xml"/> - - <!-- Add packages here --> </struts> Modified: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundleAccessor.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundleAccessor.java?rev=632748&r1=632747&r2=632748&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundleAccessor.java (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundleAccessor.java Sun Mar 2 04:33:04 2008 @@ -4,6 +4,7 @@ import java.io.InputStream; import java.net.URL; import java.util.Map; +import java.util.Set; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; @@ -12,9 +13,7 @@ String CURRENT_BUNDLE_NAME = "__bundle_name__"; - void setBundles(Map<String, Bundle> bundles); - - void setBundleContext(BundleContext bundleContext); + void init(Map<String, Bundle> bundles, BundleContext bundleContext, Map<String, String> packageToBundle); Class loadClass(String name) throws ClassNotFoundException; @@ -22,5 +21,8 @@ URL loadResource(String name); - void setPackageToBundleMapping(Map<String, String> packageToBundle); + Map<String, Bundle> getBundles(); + + Set<String> getPackagesByBundle(Bundle bundle); + } Modified: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundlePackageLoader.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundlePackageLoader.java?rev=632748&r1=632747&r2=632748&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundlePackageLoader.java (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundlePackageLoader.java Sun Mar 2 04:33:04 2008 @@ -43,7 +43,9 @@ } finally { ctx.put(BundleAccessor.CURRENT_BUNDLE_NAME, null); } - return new ArrayList<PackageConfig>(config.getPackageConfigs().values()); + List<PackageConfig> list = new ArrayList<PackageConfig>(config.getPackageConfigs().values()); + list.removeAll(pkgConfigs.values()); + return list; } static class BundleConfigurationProvider extends XmlConfigurationProvider { Modified: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DefaultBundleAccessor.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DefaultBundleAccessor.java?rev=632748&r1=632747&r2=632748&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DefaultBundleAccessor.java (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DefaultBundleAccessor.java Sun Mar 2 04:33:04 2008 @@ -3,11 +3,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; import org.osgi.framework.Bundle; @@ -16,6 +12,8 @@ import com.opensymphony.xwork2.util.logging.Logger; import com.opensymphony.xwork2.util.logging.LoggerFactory; import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.ActionProxy; import com.opensymphony.xwork2.config.entities.ActionConfig; public class DefaultBundleAccessor implements BundleAccessor { @@ -26,6 +24,7 @@ private Map<String, Bundle> bundles = new HashMap<String, Bundle>(); private BundleContext bundleContext; private Map<String, String> packageToBundle; + private Map<Bundle, Set<String>> packagesByBundle; public DefaultBundleAccessor() { self = this; @@ -36,19 +35,28 @@ return self; } - public void setBundles(Map<String,Bundle> bundles) { - this.bundles = bundles; - } - - public void setBundleContext(BundleContext bundleContext) { + public void init(Map<String,Bundle> bundles, BundleContext bundleContext, Map<String, String> packageToBundle) { + this.bundles = Collections.unmodifiableMap(bundles); this.bundleContext = bundleContext; + this.packageToBundle = Collections.unmodifiableMap(packageToBundle); + this.packagesByBundle = new HashMap<Bundle, Set<String>>(); + for (Map.Entry<String,String> entry : packageToBundle.entrySet()) { + Bundle bundle = bundles.get(entry.getValue()); + Set<String> pkgs = packagesByBundle.get(bundle); + if (pkgs == null) { + pkgs = new HashSet<String>(); + packagesByBundle.put(bundle, pkgs); + } + pkgs.add(entry.getKey()); + } + this.packagesByBundle = Collections.unmodifiableMap(packagesByBundle); } public Class<?> loadClass(String className) throws ClassNotFoundException { Class cls = null; Bundle bundle = getCurrentBundle(); if (bundle != null) { - bundle.loadClass(className); + cls = bundle.loadClass(className); LOG.debug("Located class #1 in bundle #2", className, bundle.getSymbolicName()); } @@ -73,8 +81,10 @@ private Bundle getCurrentBundle() { ActionContext ctx = ActionContext.getContext(); String bundleName = (String) ctx.get(CURRENT_BUNDLE_NAME); - if (bundleName != null) { - ActionConfig actionConfig = ctx.getActionInvocation().getProxy().getConfig(); + if (bundleName == null) { + ActionInvocation inv = ctx.getActionInvocation(); + ActionProxy proxy = inv.getProxy(); + ActionConfig actionConfig = proxy.getConfig(); bundleName = packageToBundle.get(actionConfig.getPackageName()); } if (bundleName != null) { @@ -105,8 +115,12 @@ return null; } - public void setPackageToBundleMapping(Map<String, String> packageToBundle) { - this.packageToBundle = packageToBundle; + public Map<String, Bundle> getBundles() { + return bundles; + } + + public Set<String> getPackagesByBundle(Bundle bundle) { + return packagesByBundle.get(bundle); } public InputStream loadResourceAsStream(String name) throws IOException { Modified: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DelegatingObjectFactory.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DelegatingObjectFactory.java?rev=632748&r1=632747&r2=632748&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DelegatingObjectFactory.java (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DelegatingObjectFactory.java Sun Mar 2 04:33:04 2008 @@ -3,12 +3,15 @@ import java.util.Map; import com.opensymphony.xwork2.ObjectFactory; +import com.opensymphony.xwork2.config.PackageProvider; import com.opensymphony.xwork2.inject.Container; import com.opensymphony.xwork2.inject.Inject; +import org.apache.struts2.util.ObjectFactoryDestroyable; -public class DelegatingObjectFactory extends ObjectFactory { +public class DelegatingObjectFactory extends ObjectFactory implements ObjectFactoryDestroyable { private ObjectFactory delegateObjectFactory; private BundleAccessor bundleResourceLoader; + private OsgiConfigurationProvider osgiConfigurationProvider; @Inject public void setDelegateObjectFactory(@Inject Container container, @@ -44,6 +47,15 @@ return bundleResourceLoader.loadClass(className); } } - - + + public void destroy() { + if (osgiConfigurationProvider != null) { + osgiConfigurationProvider.destroy(); + } + } + + @Inject("osgi") + public void setOsgiConfigurationProvider(PackageProvider osgiConfigurationProvider) { + this.osgiConfigurationProvider = (OsgiConfigurationProvider) osgiConfigurationProvider; + } } Modified: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java?rev=632748&r1=632747&r2=632748&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java Sun Mar 2 04:33:04 2008 @@ -67,8 +67,6 @@ @Inject public void setBundleAccessor(BundleAccessor acc) { - acc.setBundles(bundles); - acc.setBundleContext(bundleContext); this.bundleAccessor = acc; } @@ -122,7 +120,7 @@ } } } - bundleAccessor.setPackageToBundleMapping(packageToBundle); + bundleAccessor.init(bundles, bundleContext, packageToBundle); bundlesChanged = false; } @@ -144,8 +142,12 @@ "org.osgi.service.packageadmin; version=1.2.0," + "org.osgi.service.startlevel; version=1.0.0," + "org.osgi.service.url; version=1.0.0," + + "org.apache.struts2.osgi; version=1.0.0," + "org.apache.struts2.dispatcher; version=1.0.0," + - "org.apache.xwork2; version=1.0.0" + + "com.opensymphony.xwork2.config; version=1.0.0," + + "com.opensymphony.xwork2.config.entities; version=1.0.0," + + "com.opensymphony.xwork2.inject; version=1.0.0," + + "com.opensymphony.xwork2; version=1.0.0" + getSystemPackages(systemProperties) + strutsProperties.getProperty("xwork")); @@ -164,7 +166,7 @@ configMap.put(FelixConstants.EMBEDDED_EXECUTION_PROP, "true"); configMap.put(FelixConstants.SERVICE_URLHANDLERS_PROP, "false"); configMap.put("org.osgi.framework.bootdelegation", "org.apache.*"); - configMap.put("osgi.parentClassloader", "app"); + //configMap.put("osgi.parentClassloader", "app"); configMap.put("felix.log.level", "4"); configMap.put(FelixConstants.BUNDLE_CLASSPATH, "."); @@ -228,9 +230,10 @@ } public void bundleChanged(BundleEvent evt) { - if (evt.getType() == BundleEvent.STARTED) { + if (evt.getType() == BundleEvent.STARTED && evt.getBundle().getSymbolicName() != null) { LOG.info("Started bundle #1", evt.getBundle().getSymbolicName()); - bundles.put(evt.getBundle().getLocation(), evt.getBundle()); + + bundles.put(evt.getBundle().getSymbolicName(), evt.getBundle()); bundlesChanged = true; } } Added: struts/sandbox/trunk/struts2-osgi-plugin/pom.xml URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/pom.xml?rev=632748&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/pom.xml (added) +++ struts/sandbox/trunk/struts2-osgi-plugin/pom.xml Sun Mar 2 04:33:04 2008 @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* + * $Id: pom.xml 614532 2008-01-23 13:40:42Z mrdon $ + * + * 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> + <groupId>org.apache.struts</groupId> + <artifactId>struts2-osgi-plugin-parent</artifactId> + <packaging>pom</packaging> + <version>1-SNAPSHOT</version> + <name>Struts OSGi Plugin Parent</name> + + <modules> + <module>admin-bundle</module> + <module>plugin</module> + </modules> +</project>