/* | |
* 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; | |
} | |
} |