You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by cl...@apache.org on 2013/02/27 16:59:44 UTC
svn commit: r1450821 [5/5] - in /felix/trunk/ipojo/handler/jmx: ./ doc/
jmx-handler-it/ jmx-handler-it/src/ jmx-handler-it/src/it/
jmx-handler-it/src/it/jmx-it/ jmx-handler-it/src/it/jmx-it/src/
jmx-handler-it/src/it/jmx-it/src/main/ jmx-handler-it/src...
Added: felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MBeanHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MBeanHandler.java?rev=1450821&view=auto
==============================================================================
--- felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MBeanHandler.java (added)
+++ felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MBeanHandler.java Wed Feb 27 15:59:42 2013
@@ -0,0 +1,668 @@
+/*
+ * 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.ipojo.handlers.jmx;
+
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Properties;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+import org.apache.felix.ipojo.FieldInterceptor;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * This class implements iPOJO Handler. it builds the dynamic MBean from
+ * metadata.xml and exposes it to the MBean Server.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MBeanHandler extends PrimitiveHandler {
+
+ /**
+ * The name of the MBeanRegistration postDeregister method.
+ */
+ public static final String POST_DEREGISTER_METH_NAME = "postDeregister";
+
+ /**
+ * The name of the MBeanRegistration preDeregister method.
+ */
+ public static final String PRE_DEREGISTER_METH_NAME = "preDeregister";
+
+ /**
+ * The name of the MBeanRegistration postRegister method.
+ */
+ public static final String POST_REGISTER_METH_NAME = "postRegister";
+
+ /**
+ * The name of the MBeanRegistration preRegister method.
+ */
+ public static final String PRE_REGISTER_METH_NAME = "preRegister";
+
+ /**
+ * The name of the global configuration element.
+ */
+ private static final String JMX_CONFIG_ELT = "config";
+
+ /**
+ * The name of the global configuration element.
+ */
+ private static final String JMX_CONFIG_ALT_ELT = "JmxBean";
+
+ /**
+ * The name of the component object full name attribute.
+ */
+ private static final String JMX_OBJ_NAME_ELT = "objectName";
+
+ /**
+ * The name of the component object name domain attribute.
+ */
+ private static final String JMX_OBJ_NAME_DOMAIN_ELT = "domain";
+
+ /**
+ * The name of the component object name attribute.
+ */
+ private static final String JMX_OBJ_NAME_WO_DOMAIN_ELT = "name";
+
+ /**
+ * The name of the attribute indicating if the handler uses MOSGi MBean server.
+ */
+ private static final String JMX_USES_MOSGI_ELT = "usesMOSGi";
+
+ /**
+ * The name of a method element.
+ */
+ private static final String JMX_METHOD_ELT = "method";
+
+ /**
+ * The alternative name of a method element.
+ */
+ private static final String JMX_METHOD_ELT_ALT = "JmxMethod";
+
+ /**
+ * The name of the property or method name attribute.
+ */
+ private static final String JMX_NAME_ELT = "name";
+
+ /**
+ * The name of a method description attribute.
+ */
+ private static final String JMX_DESCRIPTION_ELT = "description";
+
+ /**
+ * The name of a property element.
+ */
+ private static final String JMX_PROPERTY_ELT = "property";
+
+ /**
+ * The alternative name of a property element.
+ */
+ private static final String JMX_PROPERTY_ELT_ALT = "JmxProperty";
+
+ /**
+ * The name of the field attribute.
+ */
+ private static final String JMX_FIELD_ELT = "field";
+
+ /**
+ * The name of the notification attribute.
+ */
+ private static final String JMX_NOTIFICATION_ELT = "notification";
+
+ /**
+ * The name of the rights attribute.
+ */
+ private static final String JMX_RIGHTS_ELT = "rights";
+
+ /**
+ * The instance manager. Used to store the InstanceManager instance.
+ */
+ private InstanceManager m_instanceManager;
+ /**
+ * The service registration. Used to register and unregister the Dynamic MBean.
+ */
+ private ServiceRegistration m_serviceRegistration;
+ /**
+ * Stores data when parsing metadata.xml.
+ */
+ private JmxConfigFieldMap m_jmxConfigFieldMap;
+ /**
+ * Stores the Dynamic MBean.
+ */
+ private DynamicMBeanImpl m_MBean;
+ /**
+ * Constant storing the name of the class.
+ */
+ private String m_namespace = "org.apache.felix.ipojo.handlers.jmx";
+ /**
+ * The flag used to inform if we use the MOSGi framework.
+ */
+ private boolean m_usesMOSGi;
+ /**
+ * The ObjectName used to register the MBean.
+ */
+ private ObjectName m_objectName;
+ /**
+ * The flag used to inform if the MBean is registered.
+ */
+ private boolean m_registered;
+ /**
+ * The ObjectName specified in handler configuration. It can be null.
+ */
+ private String m_completeObjNameElt;
+ /**
+ * The ObjectName without domain specified in handler configuration. It can be null.
+ */
+ private String m_objNameWODomainElt;
+
+ /**
+ * The ObjectName domain specified in handler configuration. It can be null.
+ */
+ private String m_domainElt;
+ /**
+ * The flag informing if the POJO implements the MBeanRegistration interface.
+ */
+ private boolean m_registerCallbacks;
+ /**
+ * The preRegister method of MBeanRegistration interface. It is null if POJO doesn't implement MBeanRegistration interface.
+ */
+ private MethodMetadata m_preRegisterMeth;
+ /**
+ * The postRegister method of MBeanRegistration interface. It is null if POJO doesn't implement MBeanRegistration interface.
+ */
+ private MethodMetadata m_postRegisterMeth;
+ /**
+ * The preDeregister method of MBeanRegistration interface. It is null if POJO doesn't implement MBeanRegistration interface.
+ */
+ private MethodMetadata m_preDeregisterMeth;
+ /**
+ * The postDeregister method of MBeanRegistration interface. It is null if POJO doesn't implement MBeanRegistration interface.
+ */
+ private MethodMetadata m_postDeregisterMeth;
+
+ /**
+ * Constructs the structure JmxConfigFieldMap and the Dynamic Mbean.
+ *
+ * @param metadata the component metadata
+ * @param dict the instance configuration
+ */
+ public void configure(Element metadata, Dictionary dict) {
+
+ PojoMetadata manipulation = getPojoMetadata();
+
+ m_instanceManager = getInstanceManager();
+
+ m_jmxConfigFieldMap = new JmxConfigFieldMap();
+
+ // Build the hashmap
+ Element[] mbeans = metadata.getElements(JMX_CONFIG_ELT, m_namespace);
+ if (mbeans == null || mbeans.length == 0) {
+ mbeans = metadata.getElements(JMX_CONFIG_ALT_ELT, m_namespace);
+ }
+
+ if (mbeans.length != 1) {
+ error("A component must have exactly one " + JMX_CONFIG_ELT + " or " + JMX_CONFIG_ALT_ELT + " element.");
+ error("The JMX handler configuration is ignored.");
+ return;
+ }
+
+ Element mbean = mbeans[0];
+
+ // retrieve kind of MBeanServer to use
+ m_usesMOSGi = Boolean.parseBoolean(mbean.getAttribute(JMX_USES_MOSGI_ELT));
+
+ // retrieve object name
+ m_completeObjNameElt = mbean.getAttribute(JMX_OBJ_NAME_ELT);
+ m_domainElt = mbean.getAttribute(JMX_OBJ_NAME_DOMAIN_ELT);
+ m_objNameWODomainElt = mbean.getAttribute(JMX_OBJ_NAME_WO_DOMAIN_ELT);
+
+ // test if Pojo is interested in registration callbacks
+ m_registerCallbacks = manipulation
+ .isInterfaceImplemented(MBeanRegistration.class.getName());
+ if (m_registerCallbacks) {
+ // don't need to check that methods exist, the pojo implements
+ // MBeanRegistration interface
+ String[] preRegisterParams = { MBeanServer.class.getName(),
+ ObjectName.class.getName() };
+ m_preRegisterMeth = manipulation.getMethod(PRE_REGISTER_METH_NAME,
+ preRegisterParams);
+
+ String[] postRegisterParams = { Boolean.class.getName() };
+ m_postRegisterMeth = manipulation.getMethod(
+ POST_REGISTER_METH_NAME, postRegisterParams);
+
+ m_preDeregisterMeth = manipulation.getMethod(
+ PRE_DEREGISTER_METH_NAME, new String[0]);
+
+ m_postDeregisterMeth = manipulation.getMethod(
+ POST_DEREGISTER_METH_NAME, new String[0]);
+ }
+
+ // set property
+ Element[] attributes = mbean.getElements(JMX_PROPERTY_ELT, m_namespace);
+ Element[] attributesAlt = mbean.getElements(JMX_PROPERTY_ELT_ALT, m_namespace);
+ List<Element> listOfAttributes = new ArrayList<Element>();
+ if (attributes != null) {
+ listOfAttributes.addAll(Arrays.asList(attributes));
+ }
+ if (attributesAlt != null) {
+ listOfAttributes.addAll(Arrays.asList(attributesAlt));
+ }
+
+ Element[] attributesOld = mbeans[0].getElements(JMX_PROPERTY_ELT);
+ if (attributesOld != null) {
+ warn("The JMX property element should use the '" + m_namespace + "' namespace.");
+ listOfAttributes.addAll(Arrays.asList(attributesOld));
+ }
+
+ for (Element attribute : listOfAttributes) {
+ boolean notif = false;
+ String rights;
+ String name;
+ String field = attribute.getAttribute(JMX_FIELD_ELT);
+
+ if (attribute.containsAttribute(JMX_NAME_ELT)) {
+ name = attribute.getAttribute(JMX_NAME_ELT);
+ } else {
+ name = field;
+ }
+ if (attribute.containsAttribute(JMX_RIGHTS_ELT)) {
+ rights = attribute.getAttribute(JMX_RIGHTS_ELT);
+ } else {
+ rights = "r";
+ }
+
+ PropertyField property = new PropertyField(name, field, rights,
+ getTypeFromAttributeField(field, manipulation));
+
+ if (attribute.containsAttribute(JMX_NOTIFICATION_ELT)) {
+ notif = Boolean.parseBoolean(attribute
+ .getAttribute(JMX_NOTIFICATION_ELT));
+ }
+
+ property.setNotifiable(notif);
+
+ if (notif) {
+ // add the new notifiable property in structure
+ NotificationField notification = new NotificationField(
+ name, this.getClass().getName() + "." + field, null);
+ m_jmxConfigFieldMap.addNotificationFromName(name,
+ notification);
+ }
+ m_jmxConfigFieldMap.addPropertyFromName(name, property);
+ getInstanceManager().register(manipulation.getField(field),
+ this);
+ info("property exposed:" + name + " " + field + ":"
+ + getTypeFromAttributeField(field, manipulation) + " "
+ + rights + ", Notif=" + notif);
+ }
+
+ // set methods
+ Element[] methods = mbean.getElements(JMX_METHOD_ELT, m_namespace);
+ Element[] methodsAlt = mbean.getElements(JMX_METHOD_ELT_ALT, m_namespace);
+ List<Element> listOfMethods = new ArrayList<Element>();
+ if (methods != null) {
+ listOfMethods.addAll(Arrays.asList(methods));
+ }
+ if (methodsAlt != null) {
+ listOfMethods.addAll(Arrays.asList(methodsAlt));
+ }
+
+ Element[] methodsOld = mbeans[0].getElements(JMX_PROPERTY_ELT);
+ if (methodsOld != null) {
+ warn("The JMX method element should use the '" + m_namespace + "' namespace.");
+ listOfMethods.addAll(Arrays.asList(methodsOld));
+ }
+
+ for (Element method : listOfMethods) {
+ String name = method.getAttribute(JMX_NAME_ELT);
+ if (name == null) {
+ name = method.getAttribute("method");
+ }
+ String description = null;
+ if (method.containsAttribute(JMX_DESCRIPTION_ELT)) {
+ description = method.getAttribute(JMX_DESCRIPTION_ELT);
+ }
+
+ MethodField[] meth = getMethodsFromName(name, manipulation,
+ description);
+
+ for (int j = 0; j < meth.length; j++) {
+ m_jmxConfigFieldMap.addMethodFromName(name, meth[j]);
+
+ info("method exposed:" + meth[j].getReturnType() + " " + name);
+ }
+ }
+
+ }
+
+ /**
+ * Registers the Dynamic Mbean.
+ */
+ public void start() {
+ // create the corresponding MBean
+ if (m_registerCallbacks) {
+ m_MBean = new DynamicMBeanWRegisterImpl(m_jmxConfigFieldMap,
+ m_instanceManager, m_preRegisterMeth, m_postRegisterMeth,
+ m_preDeregisterMeth, m_postDeregisterMeth);
+ } else {
+ m_MBean = new DynamicMBeanImpl(m_jmxConfigFieldMap,
+ m_instanceManager);
+ }
+
+ if (m_usesMOSGi) {
+ // use whiteboard pattern to register MBean
+
+ if (m_serviceRegistration != null) {
+ m_serviceRegistration.unregister();
+ }
+
+ // Register the ManagedService
+ BundleContext bundleContext = m_instanceManager.getContext();
+ Properties properties = new Properties();
+ try {
+ m_objectName = new ObjectName(getObjectNameString());
+
+ properties.put("jmxagent.objectName", m_objectName.toString());
+
+ m_serviceRegistration = bundleContext.registerService(
+ javax.management.DynamicMBean.class.getName(), m_MBean,
+ properties);
+
+ m_registered = true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ try {
+ m_objectName = new ObjectName(getObjectNameString());
+ ObjectInstance instance = ManagementFactory
+ .getPlatformMBeanServer().registerMBean(m_MBean,
+ m_objectName);
+
+ // we must retrieve object name used to register the MBean.
+ // It can have been changed by preRegister method of
+ // MBeanRegistration interface.
+ if (m_registerCallbacks) {
+ m_objectName = instance.getObjectName();
+ }
+
+ m_registered = true;
+ } catch (Exception e) {
+ error("Registration of MBean failed.", e);
+ }
+ }
+ }
+
+ /**
+ * Returns the object name of the exposed component.
+ *
+ * @return the object name of the exposed component.
+ */
+ private String getObjectNameString() {
+ if (m_completeObjNameElt != null) {
+ return m_completeObjNameElt;
+ }
+
+ String domain;
+ if (m_domainElt != null) {
+ domain = m_domainElt;
+ } else {
+ domain = getPackageName(m_instanceManager.getClassName());
+ }
+
+ String name = "type=" + m_instanceManager.getClassName() + ",instance="
+ + m_instanceManager.getInstanceName();
+ if (m_objNameWODomainElt != null) {
+ name = "name=" + m_objNameWODomainElt;
+ }
+
+ StringBuffer sb = new StringBuffer();
+ if ((domain != null) && (domain.length() > 0)) {
+ sb.append(domain + ":");
+ }
+ sb.append(name);
+
+ info("Computed Objectname: " + sb.toString());
+
+ return sb.toString();
+ }
+
+ /**
+ * Extracts the package name from of given type.
+ *
+ * @param className the type name.
+ * @return the package name of the given type.
+ */
+ private String getPackageName(String className) {
+ String packageName = "";
+
+ int plotIdx = className.lastIndexOf(".");
+ if (plotIdx != -1) {
+ packageName = className.substring(0, plotIdx);
+ }
+
+ return packageName;
+ }
+
+ /**
+ * Unregisters the Dynamic Mbean.
+ */
+ public void stop() {
+ if (m_usesMOSGi) {
+ if (m_serviceRegistration != null) {
+ m_serviceRegistration.unregister();
+ }
+ } else {
+ if (m_objectName != null) {
+ try {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(
+ m_objectName);
+ } catch (Exception e) {
+ error("Unregistration of MBean failed.", e);
+ }
+ m_objectName = null;
+ }
+ }
+
+ m_MBean = null;
+ m_registered = false;
+ }
+
+ /**
+ * Called when a POJO member is modified externally.
+ *
+ * @param pojo the modified POJO object
+ * @param fieldName the name of the modified field
+ * @param value the new value of the field
+ * @see FieldInterceptor#onSet(Object, String, Object)
+ */
+ public void onSet(Object pojo, String fieldName, Object value) {
+ // Check if the field is a configurable property
+
+ PropertyField propertyField = (PropertyField) m_jmxConfigFieldMap
+ .getPropertyFromField(fieldName);
+ if (propertyField != null) {
+ if (propertyField.isNotifiable()) {
+ // TODO should send notif only when value has changed to a value
+ // different than the last one.
+ m_MBean.sendNotification(propertyField.getName() + " changed",
+ propertyField.getName(), propertyField.getType(),
+ propertyField.getValue(), value);
+ }
+ propertyField.setValue(value);
+ }
+ }
+
+ /**
+ * Called when a POJO member is read by the MBean.
+ *
+ * @param pojo the read POJO object.
+ * @param fieldName the name of the modified field
+ * @param value the old value of the field
+ * @return the (injected) value of the field
+ * @see FieldInterceptor#onGet(Object, String, Object)
+ */
+ public Object onGet(Object pojo, String fieldName, Object value) {
+
+ // Check if the field is a configurable property
+ PropertyField propertyField = (PropertyField) m_jmxConfigFieldMap
+ .getPropertyFromField(fieldName);
+ if (propertyField != null) {
+ // Do we have a value to inject ?
+ Object v = propertyField.getValue();
+ if (v == null) {
+ String type = propertyField.getType();
+ if ("boolean".equals(type)) { v = Boolean.FALSE; }
+ else if ("byte".equals(type)) { v = new Byte((byte) 0); }
+ else if ("short".equals(type)) { v = new Short((short) 0); }
+ else if ("int".equals(type)) { v = new Integer(0); }
+ else if ("long".equals(type)) { v = new Long(0); }
+ else if ("float".equals(type)) { v = new Float(0); }
+ else if ("double".equals(type)) { v =new Double(0); }
+ else if ("char".equals(type)) { v = new Character((char) 0); }
+
+ return v;
+ }
+ m_instanceManager.onSet(pojo, fieldName, propertyField.getValue());
+ return propertyField.getValue();
+ }
+ return value;
+ }
+
+ /**
+ * Gets the type from a field name.
+ *
+ * @param fieldRequire the name of the required field
+ * @param manipulation the metadata extracted from metadata.xml file
+ * @return the type of the field or {@code null} if it wasn't found
+ */
+ private static String getTypeFromAttributeField(String fieldRequire,
+ PojoMetadata manipulation) {
+
+ FieldMetadata field = manipulation.getField(fieldRequire);
+ if (field == null) {
+ return null;
+ } else {
+ return FieldMetadata.getReflectionType(field.getFieldType());
+ }
+ }
+
+ /**
+ * Gets all the methods available which get this name.
+ *
+ * @param methodName the name of the required methods
+ * @param manipulation the metadata extract from metadata.xml file
+ * @param description the description which appears in JMX console
+ * @return the array of methods with the right name
+ */
+ private MethodField[] getMethodsFromName(String methodName,
+ PojoMetadata manipulation, String description) {
+
+ MethodMetadata[] methods = manipulation.getMethods(methodName);
+ if (methods.length == 0) {
+ return null;
+ }
+
+ MethodField[] ret = new MethodField[methods.length];
+
+ if (methods.length == 1) {
+ ret[0] = new MethodField(methods[0], description);
+ return ret;
+ } else {
+ for (int i = 0; i < methods.length; i++) {
+ ret[i] = new MethodField(methods[i], description);
+ }
+ return ret;
+ }
+ }
+
+ /**
+ * Gets the JMX handler description.
+ *
+ * @return the JMX handler description.
+ * @see org.apache.felix.ipojo.Handler#getDescription()
+ */
+ public HandlerDescription getDescription() {
+ return new JMXHandlerDescription(this);
+ }
+
+ /**
+ * Returns the objectName used to register the MBean. If the MBean is not registered, return an empty string.
+ *
+ * @return the objectName used to register the MBean.
+ * @see org.apache.felix.ipojo.Handler#getDescription()
+ */
+ public String getUsedObjectName() {
+ if (m_objectName != null) {
+ return m_objectName.toString();
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Returns true if the MBean is registered.
+ *
+ * @return true if the MBean is registered.
+ */
+ public boolean isRegistered() {
+ return m_registered;
+ }
+
+ /**
+ * Returns true if the MBean must be registered thanks to white board pattern of MOSGi.
+ *
+ * @return {@code true} if the MBean must be registered thanks to white board pattern of MOSGi, false otherwise.
+ */
+ public boolean isUsesMOSGi() {
+ return m_usesMOSGi;
+ }
+
+ /**
+ * Returns true if the MOSGi framework is present on the OSGi platform.
+ *
+ * @return {@code true} if the MOSGi framework is present on the OSGi platform, false otherwise.
+ */
+ public boolean isMOSGiExists() {
+ for (Bundle bundle : m_instanceManager.getContext().getBundles()) {
+ String symbolicName = bundle.getSymbolicName();
+ if ("org.apache.felix.mosgi.jmx.agent".equals(symbolicName)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
Added: felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MethodField.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MethodField.java?rev=1450821&view=auto
==============================================================================
--- felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MethodField.java (added)
+++ felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MethodField.java Wed Feb 27 15:59:42 2013
@@ -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.ipojo.handlers.jmx;
+
+import javax.management.MBeanParameterInfo;
+
+import org.apache.felix.ipojo.parser.MethodMetadata;
+
+/**
+ * This class builds a method JMX description.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MethodField {
+
+ /**
+ * Stores the method description.
+ */
+ private String m_description;
+ /**
+ * Stores the method properties.
+ */
+ private MethodMetadata m_method;
+
+ /**
+ * Constructor.
+ *
+ * @param method the method properties
+ * @param description the method description
+ */
+ public MethodField(MethodMetadata method, String description) {
+ this.m_method = method;
+ this.m_description = description;
+
+ }
+
+ /**
+ * Gets the method.
+ * @return the method
+ */
+ public MethodMetadata getMethod() {
+ return m_method;
+ }
+
+ /**
+ * Gets the description.
+ * @return the description
+ */
+ public String getDescription() {
+ return m_description;
+ }
+
+ /**
+ * Gets the name.
+ * @return the name
+ */
+ public String getName() {
+ return m_method.getMethodName();
+ }
+
+ /**
+ * Gets the parameter in JMX format.
+ *
+ * @return info on JMX format
+ */
+ public MBeanParameterInfo[] getParams() {
+ MBeanParameterInfo[] mbean = new MBeanParameterInfo[m_method
+ .getMethodArguments().length];
+ for (int i = 0; i < m_method.getMethodArguments().length; i++) {
+ mbean[i] = new MBeanParameterInfo("arg" + i, m_method
+ .getMethodArguments()[i], null);
+ }
+ return mbean;
+ }
+
+ public String[] getSignature() {
+ return m_method.getMethodArguments();
+ }
+
+ public String getReturnType() {
+ return m_method.getMethodReturn();
+ }
+
+}
Added: felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/NotificationField.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/NotificationField.java?rev=1450821&view=auto
==============================================================================
--- felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/NotificationField.java (added)
+++ felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/NotificationField.java Wed Feb 27 15:59:42 2013
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.handlers.jmx;
+
+import javax.management.MBeanNotificationInfo;
+
+/**
+ * This class builds the notification description structure.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class NotificationField {
+ /**
+ * The name of the notification.
+ */
+ private String m_name;
+ /**
+ * The description of the notification.
+ */
+ private String m_description;
+ /**
+ * The field of the notification.
+ */
+ private String m_field;
+
+ /**
+ * Constructor.
+ *
+ * @param name the name of the notification
+ * @param field the field which send a notification when it is modified
+ * @param description the description which appears in JMX console
+ */
+
+ public NotificationField(String name, String field, String description) {
+ this.m_name = name;
+ this.m_field = field;
+ this.m_description = description;
+ }
+
+ /**
+ * Returns the MBeanNotificationInfo from this class.
+ *
+ * @return the type of the field or {@code null} if it wasn't found
+ */
+ public MBeanNotificationInfo getNotificationInfo() {
+ String[] notificationTypes = new String[1];
+ notificationTypes[0] = m_field;
+ MBeanNotificationInfo mbni = new MBeanNotificationInfo(
+ notificationTypes, m_name, m_description);
+ return mbni;
+ }
+}
Added: felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/PropertyField.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/PropertyField.java?rev=1450821&view=auto
==============================================================================
--- felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/PropertyField.java (added)
+++ felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/PropertyField.java Wed Feb 27 15:59:42 2013
@@ -0,0 +1,196 @@
+/*
+ * 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.ipojo.handlers.jmx;
+
+/**
+ * This class build the notification description structure.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class PropertyField {
+
+ /**
+ * The name of the notification.
+ */
+ private String m_name;
+ /**
+ * The name of the notification.
+ */
+ private String m_field;
+ /**
+ * The name of the notification.
+ */
+ private String m_rights;
+ /**
+ * The name of the notification.
+ */
+ private String m_type;
+ /**
+ * The name of the notification.
+ */
+ private Object m_value;
+ /**
+ * The name of the notification.
+ */
+ private boolean m_notification;
+
+ /**
+ * Constructor.
+ *
+ * @param name the name of the properety
+ * @param field the field which send a notification when it is modified
+ * @param rights the rights of the attribute (ie: 'r' or 'w')
+ * @param type the type of the attribute
+ */
+ public PropertyField(String name, String field, String rights, String type) {
+ this.setName(name);
+ this.setField(field);
+ this.m_type = type;
+ if (isRightsValid(rights)) {
+ this.setRights(rights);
+ } else {
+ this.setField("r"); // default rights is read only
+ }
+ }
+
+ /**
+ * Returns the field.
+ * @return the field
+ */
+ public String getField() {
+ return m_field;
+ }
+
+ /**
+ * Modifies the field.
+ * @param field the new field
+ */
+ public void setField(String field) {
+ this.m_field = field;
+ }
+
+ /**
+ * Returns the name.
+ * @return the name
+ */
+ public String getName() {
+ return m_name;
+ }
+
+ /**
+ * Modifies the name.
+ * @param name the new name
+ */
+ public void setName(String name) {
+ this.m_name = name;
+ }
+
+ /**
+ * Returns the rights.
+ * @return the rights
+ */
+ public String getRights() {
+ return m_rights;
+ }
+
+ /**
+ * Modifies the rights.
+ * @param rights the new rights
+ */
+ public void setRights(String rights) {
+ this.m_rights = rights;
+ }
+
+ /**
+ * Returns the value.
+ * @return the value
+ */
+ public Object getValue() {
+ return m_value;
+ }
+
+ /**
+ * Modifies the value.
+ * @param value the new value
+ */
+ public void setValue(Object value) {
+ this.m_value = value;
+ }
+
+ /**
+ * Returns the type.
+ * @return the type
+ */
+ public String getType() {
+ return this.m_type;
+ }
+
+ /**
+ * Returns the description.
+ * @return the description
+ */
+ public String getDescription() {
+ //TODO Implement this method.
+ return null;
+ }
+
+ /**
+ * Returns true if this property field is readable, false otherwise.
+ * @return {@code true} if this property field is readable, {@code false} otherwise.
+ */
+ public boolean isReadable() {
+ return this.getRights().equals("r") || this.getRights().equals("w");
+ }
+
+ /**
+ * Returns true if this property field is writable, false otherwise.
+ * @return {@code true} if this property field is writable, {@code false} otherwise.
+ */
+ public boolean isWritable() {
+ return this.getRights().equals("w");
+ }
+
+ /**
+ * Returns true if this property field is notifiable, false otherwise.
+ * @return {@code true} if this property field is notifiable, {@code false} otherwise.
+ */
+ public boolean isNotifiable() {
+ return this.m_notification;
+ }
+
+ /**
+ * Modify the notifiability of this property field.
+ * @param value the new notifiability of this property field.
+ */
+ public void setNotifiable(boolean value) {
+ this.m_notification = value;
+ }
+
+ /**
+ * Is the rights is valid or not ? (ie = 'r' || 'w').
+ *
+ * @param rights string representing the rights
+ * @return boolean : return {@code true} if rights = 'r' or 'w'
+ */
+ public static boolean isRightsValid(String rights) {
+ return rights != null && (rights.equals("r") || rights.equals("w"));
+ }
+
+}
Added: felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/resources/jmx.xsd
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/resources/jmx.xsd?rev=1450821&view=auto
==============================================================================
--- felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/resources/jmx.xsd (added)
+++ felix/trunk/ipojo/handler/jmx/jmx-handler/src/main/resources/jmx.xsd Wed Feb 27 15:59:42 2013
@@ -0,0 +1,177 @@
+<!--
+ 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.
+-->
+<xs:schema targetNamespace="org.apache.felix.ipojo.handlers.jmx"
+ xmlns="org.apache.felix.ipojo.handlers.jmx"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+ <xs:element name="config" type="JMXType"></xs:element>
+
+ <xs:complexType name="JMXType">
+
+ <xs:annotation>
+ <xs:documentation>
+ Description of a JMX managed component.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="method" type="JMXMethod">
+ <xs:annotation>
+ <xs:documentation>
+ The list of methods to expose.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="property" type="JMXProperty">
+ <xs:annotation>
+ <xs:documentation>
+ The list of attributes to expose.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:choice>
+ <xs:attribute name="usesMOSGi" type="xs:boolean"
+ use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ Determines if the component must be register on the
+ MOSGi MBean server or not.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="objectName" type="xs:string"
+ use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ The complete object name of the managed component.
+ The syntax of this attribute must be compliant with
+ the ObjectName syntax, detailed in the JMX
+ specification. If neither domain nor name attributes
+ are specified, the default value is determined by
+ the package, the type and the instance name of the
+ component. This attribute overrides the domain and
+ name attributes.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="domain" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ The domain of the managed object (i.e., the left
+ part of the object name). This attribute must be
+ compliant with the domain syntax, as described in
+ the JMX specification.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="name" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ The name property of the managed object. The value
+ of this attribute must comply with the ObjectName
+ value syntax, as described in the JMX specification.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="preRegister" type="xs:string"
+ use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ Specifies method to carry out operations before
+ beeing registered from the MBean server. The
+ signature of the specified method must be :
+ "ObjectName preRegister(MBeanServer server,
+ ObjectName name) throws Exception".
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="postRegister" type="xs:string"
+ use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ Specifies method to carry out operations after
+ beeing registered from the MBean server. The
+ signature of the specified method must be : "void
+ postRegister(Boolean registrationDone)".
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="preDeregister" type="xs:string"
+ use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ Specifies method to carry out operations before
+ beeing unregistered from the MBean server. The
+ signature of the specified method must be : "void
+ preDeregister() throws Exception".
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="postDeregister" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ Specifies method to carry out operations after
+ beeing unregistered from the MBean server. The
+ signature of the specified method must be :
+ "void postDeregister()".</xs:documentation>
+ </xs:annotation></xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="JMXProperty">
+ <xs:annotation>
+ <xs:documentation>Description of an attribute to expose.</xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="field" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The name of the component's field to expose.</xs:documentation></xs:annotation></xs:attribute>
+ <xs:attribute name="name" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The name of the property as it will appear in JMX. If unspecified, the default value is the name of the exposed field.</xs:documentation></xs:annotation></xs:attribute>
+ <xs:attribute name="rights" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specify the access permission of the exposed field.</xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:annotation>
+ <xs:documentation>Access permission of an exposed field. Accepted values are "r" (read-only access, the default value) and "w" (read and write access).</xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="r"></xs:enumeration>
+ <xs:enumeration value="w"></xs:enumeration>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="notification" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Enable or disable attribute change notification sending for this property. If set to "true", a notification is sent each time the value of the field changes.</xs:documentation></xs:annotation></xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="JMXMethod">
+ <xs:annotation>
+ <xs:documentation>Description of a method to expose.</xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="name" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The name of the method to expose. If multiple methods have the same name, all of them are exposed.</xs:documentation>
+ </xs:annotation></xs:attribute>
+ <xs:attribute name="description" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The description of the exposed method, as it will appear in JMX.</xs:documentation></xs:annotation></xs:attribute>
+ </xs:complexType>
+</xs:schema>
\ No newline at end of file
Modified: felix/trunk/ipojo/handler/jmx/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/jmx/pom.xml?rev=1450821&r1=1450820&r2=1450821&view=diff
==============================================================================
--- felix/trunk/ipojo/handler/jmx/pom.xml (original)
+++ felix/trunk/ipojo/handler/jmx/pom.xml Wed Feb 27 15:59:42 2013
@@ -16,110 +16,100 @@
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">
- <parent>
- <groupId>org.apache.felix</groupId>
- <artifactId>felix-parent</artifactId>
- <version>1.2.1</version>
- <relativePath>../../pom/pom.xml</relativePath>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <packaging>bundle</packaging>
- <name>Apache Felix iPOJO JMX Handler</name>
- <artifactId>org.apache.felix.ipojo.handler.jmx</artifactId>
- <version>1.5.0-SNAPSHOT</version>
-
- <description>
- iPOJO extension to expose instances as MBean inside a MBean Server.
- </description>
- <url>http://felix.apache.org/site/ipojo-jmx-handler.html</url>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.felix</groupId>
- <artifactId>org.apache.felix.ipojo</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.core</artifactId>
- <version>4.0.0</version>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
+<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/xsd/maven-4.0.0.xsd">
+ <parent>
<groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <extensions>true</extensions>
- <version>1.4.3</version>
- <configuration>
- <instructions>
- <Private-Package> org.apache.felix.ipojo.handlers.jmx
- </Private-Package>
- <Bundle-Name>${project.name}</Bundle-Name>
- <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
- <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
- <Bundle-Description> iPOJO JMX Handler </Bundle-Description>
- <Bundle-DocURL>
- http://felix.apache.org/site/ipojo-jmx-handler.html
- </Bundle-DocURL>
- <Include-Resource>
- META-INF/LICENSE=LICENSE,
- META-INF/NOTICE=NOTICE,
- META-INF/DEPENDENCIES=DEPENDENCIES
- </Include-Resource>
- </instructions>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>1.5</source>
- <target>1.5</target>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-ipojo-plugin</artifactId>
- <version>${project.version}</version>
- <executions>
- <execution>
- <goals>
- <goal>ipojo-bundle</goal>
- </goals>
- <configuration>
- <metadata>metadata.xml</metadata>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>rat-maven-plugin</artifactId>
- <configuration>
- <excludeSubProjects>false</excludeSubProjects>
- <useEclipseDefaultExcludes>true</useEclipseDefaultExcludes>
- <useMavenDefaultExcludes>true</useMavenDefaultExcludes>
- <excludes>
- <param>doc/**/*</param>
- <param>maven-eclipse.xml</param>
- <param>.checkstyle</param>
- <param>.externalToolBuilders/*</param>
- <param>LICENSE.asm</param>
- </excludes>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-checkstyle-plugin</artifactId>
- <configuration>
- <enableRulesSummary>false</enableRulesSummary>
- <violationSeverity>warning</violationSeverity>
- <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
- </configuration>
- </plugin>
- </plugins>
- </build>
+ <artifactId>felix-parent</artifactId>
+ <version>1.2.1</version>
+ <relativePath>../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.apache.felix.ipojo.handler.jmx-handler-project</artifactId>
+ <version>1.5.0-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Event Admin Handler Project</name>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>jmx-handler</module>
+ <module>jmx-handler-it</module>
+ </modules>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ </resource>
+ <resource>
+ <directory>.</directory>
+ <targetPath>META-INF</targetPath>
+ <includes>
+ <include>LICENSE*</include>
+ <include>NOTICE*</include>
+ <include>DEPENDENCIES*</include>
+ </includes>
+ </resource>
+ </resources>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>release</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>project</descriptorRef>
+ </descriptorRefs>
+ <!-- we don't want to attach all the assemblies, such as bz2 -->
+ <attach>false</attach>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <!-- only attach the project and bin assemblies, in tar.gz and zip flavors -->
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-assemblies</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>
+ ${project.build.directory}/${project.artifactId}-${project.version}-project.tar.gz
+ </file>
+ <classifier>project</classifier>
+ <type>tar.gz</type>
+ </artifact>
+ <artifact>
+ <file>
+ ${project.build.directory}/${project.artifactId}-${project.version}-project.zip
+ </file>
+ <classifier>project</classifier>
+ <type>zip</type>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
</project>