/* * Copyright 2005 The Apache Software Foundation * * Licensed 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.jmood.compendium; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Dictionary; import java.util.Enumeration; import java.util.Iterator; import java.util.Set; import javax.management.InstanceNotFoundException; import javax.management.MBeanRegistration; import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.NotificationBroadcasterSupport; import javax.management.ObjectName; import org.apache.felix.jmood.AgentContext; import org.apache.felix.jmood.utils.ObjectNames; import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; //import es.upm.dit.osgi.management.agent.AgentConstants; /** * This is the main class of the config admin module. As such, it is responsible for controlling all the issues related to it. This class implements * the ConfigAdminManagerMXBean which defines its management interface. It creates a ConfigurationDelegate object for each available * Configuration object. * */ public class ConfigAdminManager extends NotificationBroadcasterSupport implements MBeanRegistration, ConfigAdminManagerMBean{ /*NOTE: The spec says that ConfigurationException's should be used by management systems * in order to inform a human manager in a suitable way. However, this is not possible unless we implement the service * because nowhere in the spec is there a way of accesing those exceptions (unless the implementation of the cm chooses to log the exception, which is not even suggested in the spec) */ private MBeanServer server; private AgentContext ac; private ConfigurationAdmin cadmin; public ConfigAdminManager(AgentContext ac) { this.ac=ac; } /** * This is called before the module is loaded. It initializes the module. * @see javax.management.MBeanRegistration#preRegister(javax.management.MBeanServer, javax.management.ObjectName) */ public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception { this.server = server; return name; } /** * @see javax.management.MBeanRegistration#postRegister(java.lang.Boolean) */ public void postRegister(Boolean registrationDone) {} /** * @see javax.management.MBeanRegistration#preDeregister() */ public void preDeregister() throws Exception { //Remove the service //and remove all mbeans from this module... unregisterMBeans(); } /** * @see javax.management.MBeanRegistration#postDeregister() */ public void postDeregister() {} /** * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#listConfigurations(java.lang.String) */ public String[] listConfigurations(String filter) throws Exception { ConfigurationAdmin cad=ac.getConfigurationAdmin(); Configuration[] confs = null; if (cad!= null) { confs = cad.listConfigurations(filter); refresh(); if (confs == null) return null; } String[] result = new String[confs.length]; for (int i = 0; i < confs.length; i++) result[i] = this.getObjectName(confs[i]); return result; } /** * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#getConfiguration(java.lang.String) */ public String getConfiguration(String pid) throws Exception { //FIXME this should not be invoked //if created, the configuration is attached to the management agent's location ac.debug("ConfigAdmin, getting config for pid: "+pid); if (pid.indexOf(':') >= 0) throw new IllegalArgumentException("pid not compliant with jmx. Please remove ':' from the pid"); ConfigurationAdmin cad=ac.getConfigurationAdmin(); if (cad != null) { Configuration config = cad.getConfiguration(pid); refresh(); return this.getObjectName(config); } else return null; } /** * This method gets a configuration object related to a pid and a bundle location * @param pid Persistent ID * @param location Bundle location of the service * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#getConfiguration(java.lang.String, java.lang.String) */ public String getConfiguration(String pid, String location) throws Exception { //":" is reserved in objectnames, as a work around we do not permit pids containing it if (pid.indexOf(':') >= 0) throw new IllegalArgumentException("pid not compliant with jmx. Please remove ':' from the pid"); ConfigurationAdmin cad=ac.getConfigurationAdmin(); if (cad != null) { Configuration config = cad.getConfiguration(pid, location); refresh(); return this.getObjectName(config); } else return null; } /** * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#createFactoryConfiguration(java.lang.String) */ public String createFactoryConfiguration(String pid) throws Exception { ConfigurationAdmin cad=ac.getConfigurationAdmin(); if (cad != null) { Configuration conf = cad.createFactoryConfiguration(pid); refresh(); return this.getObjectName(conf); } else return null; } /** * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#createFactoryConfiguration(java.lang.String, java.lang.String) */ public String createFactoryConfiguration(String pid, String location) throws Exception { ConfigurationAdmin cad=ac.getConfigurationAdmin(); if (cad != null) { Configuration conf = cad.createFactoryConfiguration(pid, location); refresh(); return this.getObjectName(conf); } else return null; } /** * Delete the configurations identified by the LDAP filter * @param filter LDAP String representing the configurations that want to be deleted * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#deleteConfigurations(java.lang.String) */ public void deleteConfigurations(String filter) throws Exception { ConfigurationAdmin cad=ac.getConfigurationAdmin(); Configuration[] confs = null; if (cad!= null) { confs = cad.listConfigurations(filter); } if (confs != null) for (int i = 0; i < confs.length; i++) { confs[i].delete(); } refresh(); } /** * Removes a property from all the configurations selected by an LDAP expression * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#removePropertyFromConfigurations(java.lang.String, java.lang.String) */ public void removePropertyFromConfigurations(String filter, String name) throws Exception { ConfigurationAdmin cad=ac.getConfigurationAdmin(); Configuration[] confs = null; if (cad != null) { confs = cad.listConfigurations(filter); } if (confs != null) for (int i = 0; i < confs.length; i++) { Dictionary dic = confs[i].getProperties(); Enumeration keys = dic.keys(); while (keys.hasMoreElements()) { String key = (String) keys.nextElement(); if (key.equals(name)) { dic.remove(key); try { confs[i].update(dic); } catch (IOException e) { ac.error("Unexpected exception", (Exception)e); } } } } } /** * Updates or adds a property to configurations selected by an LDAP expression * Arrays and vectors not supported * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#addPropertyToConfigurations(java.lang.String, java.lang.String, java.lang.String, java.lang.String) */ public void addPropertyToConfigurations( String filter, String name, String value, String type) throws Exception { if (isValidType(type)) { ConfigurationAdmin cad=ac.getConfigurationAdmin(); Configuration[] confs = null; if (cad != null) { confs = cad.listConfigurations(filter); } if (confs != null) for (int i = 0; i < confs.length; i++) { Dictionary dic = confs[i].getProperties(); dic.put(name, castValueToType(type, value)); try { confs[i].update(dic); } catch (IOException e) { ac.error("Unexpected exception", (Exception)e); } } } } /** * * Validate that the value type is supported * @param type */ protected static boolean isValidType(String type) { String[] validTypes = { "String", "Integer", "Long", "Float", "Double", "Byte", "Short", "Character", "Boolean", "BigInteger", "BigDecimal" }; for (int i = 0; i < validTypes.length; i++) { if (validTypes[i].equalsIgnoreCase(type)) return true; } return false; } protected static Object castValueToType(String type, String value) { value = value.equals("") ? null : value; if (type.equals("String")) { return value == null ? new String() : new String(value); } else if (type.equals("Integer")) { return value == null ? new Integer(0) : new Integer(value); } else if (type.equals("Long")) { return value == null ? new Long(0) : new Long(value); } else if (type.equals("Float")) { return value == null ? new Float(0) : new Float(value); } else if (type.equals("Double")) { return value == null ? new Double(0) : new Double(value); } else if (type.equals("Byte")) { return value == null ? new Byte("0") : new Byte(value); } else if (type.equals("Short")) { return value == null ? new Short("0") : new Short(value); } else if (type.equals("BigInteger")) { return value == null ? new BigInteger("0") : new BigInteger(value); } else if (type.equals("BigDecimal")) { return value == null ? new BigDecimal(0) : new BigDecimal(value); } else if (type.equals("Character")) { return value == null ? new Character('a') : new Character(value.charAt(0)); } else if (type.equals("Boolean")) { return value == null ? new Boolean(false) : new Boolean(value); } else { // Unsupported type return null; } } private void registerMBeans() throws Exception{ ConfigurationAdmin cad=ac.getConfigurationAdmin(); if (cad==null) { ac.debug("could not add any conf mbean, conf admin not available"); return; } ac.debug("creating mbeans for existing config objects"); Configuration[] confs = null; //confs contains the new config objects //The old ones are in configObjects, whose key is the object name. confs = cad.listConfigurations(null); if (confs!=null) { ac.debug("Existing conf objects: "); for(int i=0;i<confs.length;i++) { ac.debug("\t"+confs[i].getPid()); //now we add the new ones String oname = this.getObjectName(confs[i]); server.registerMBean( new ConfigurationDelegate(confs[i], ac), new ObjectName(oname)); ac.debug("Succesfully registered? "+!server.queryMBeans(new ObjectName(oname), null).isEmpty()); } } } public synchronized void refresh() throws Exception { //Extremely innefficient but KISS unregisterMBeans(); registerMBeans(); } public boolean isAvailable() { return ac.getConfigurationAdmin()==null?false:true; } private void unregisterMBeans() throws MalformedObjectNameException, NullPointerException, InstanceNotFoundException, MBeanRegistrationException{ Set set = server.queryNames( new ObjectName(ObjectNames.ALL_CM_OBJECT), null); Iterator it = set.iterator(); while (it.hasNext()) { ObjectName oname=(ObjectName) it.next(); ac.debug("Unregistering config mbean: "+oname); server.unregisterMBean(oname); } } private String getObjectName(Configuration configuration) { StringBuffer posfix = new StringBuffer(); posfix.append("pid=" + configuration.getPid()); if (configuration.getFactoryPid() != null) posfix.append( ",isFactory=true,FactoryPid=" + configuration.getFactoryPid()); else posfix.append(",isFactory=false"); String oname = ObjectNames.CM_OBJECT + posfix.toString(); return oname; } }