View Javadoc

1   /*
2    * Copyright 2004-2005 Germinus XXI
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License")
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.germinus.easyconf.jmx;
17  
18  import java.lang.reflect.Constructor;
19  import java.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.HashSet;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Set;
26  
27  import javax.management.Attribute;
28  import javax.management.AttributeList;
29  import javax.management.AttributeNotFoundException;
30  import javax.management.DynamicMBean;
31  import javax.management.InvalidAttributeValueException;
32  import javax.management.MBeanAttributeInfo;
33  import javax.management.MBeanConstructorInfo;
34  import javax.management.MBeanException;
35  import javax.management.MBeanInfo;
36  import javax.management.MBeanOperationInfo;
37  import javax.management.MBeanParameterInfo;
38  import javax.management.ReflectionException;
39  
40  import com.germinus.easyconf.ComponentConfiguration;
41  import com.germinus.easyconf.ComponentProperties;
42  import com.germinus.easyconf.EasyConf;
43  
44  /***
45   * MBean wrapper for a ComponentConfiguration. <a
46   * href="ComponentConfigurationDynamicMBean.java.html"> <b><i>View Source </i>
47   * </b> </a>
48   *
49   * @author Alvaro Gonz?lez
50   * @version $Revision: 1.4 $
51   *
52   */
53  public class ComponentConfigurationDynamicMBean implements DynamicMBean {
54      /***
55       * Name of the reloadConfiguration operation. Used when invoking
56       * <code>invoke</code> method.
57       */
58      public static final String RELOAD_OPERATION_NAME = "reloadConfiguration";
59  
60      /***
61       * Name of the newProperty operations. Used when invoking
62       * <code>invoke</code> method.
63       */
64      public static final String NEW_PROPERTY_OPERATION_NAME = "newProperty";
65  
66      /***
67       * Signature of the reloadConfiguration operation. Used when invoking
68       * <code>invoke</code> method.
69       */
70      public static final String[] RELOAD_OPERATION_SIGNATURE = new String[0];
71  
72      /***
73       * Signature of the newProperty operation with one parameter.
74       * Used when invoking <code>invoke</code> method.
75       */
76      public static final String[] NEW_PROPERTY_OPERATION_SIGNATURE_1 = 
77      	new String[] { String.class.toString() };
78  
79      /***
80       * Signature of the newProperty operation with two parameters.
81       * Used when invoking <code>invoke</code> method.
82       */
83      public static final String[] NEW_PROPERTY_OPERATION_SIGNATURE_2 = 
84      	new String[] {String.class.toString(), Object.class.toString() };
85  
86      private static final String NEW_PROPERTY_OPERATION_DESCRIPTION_1 = 
87      	"Add new property to the Configuration Component. " +
88      	"The Param is the property name. Must not" +
89  		" exists another property with the same name.";
90  
91  	private static final String NEW_PROPERTY_OPERATION_DESCRIPTION_2 = 
92  		NEW_PROPERTY_OPERATION_DESCRIPTION_1 +
93  		" The second param is the initial value of the new property";
94  
95  	private static final String RELOAD_OPERATION_DESCRIPTION = 
96  		"Reloads the configuration";
97  
98  	private static final String CONSTRUCTOR_DESCRIPTION_1 = 
99  		"Constructs new MBean with the configuration of the named Component";
100 
101 	private String componentName;
102 
103 	private ComponentConfiguration componentConfiguration;
104 
105 	private MBeanAttributeInfo[] attributesInfo;
106 
107 	private Map modifiedProperties;
108 
109 	private Map newPropeties;
110 
111 	private MBeanOperationInfo[] operationInfo;
112 
113 	private MBeanConstructorInfo[] constructorsInfo;
114 
115 	/***
116 	 * Create a MBean wraping some loaded ComponentConfiguration 
117 	 * @param component
118 	 */
119 	public ComponentConfigurationDynamicMBean
120 		(ComponentConfiguration component) {
121 		super();
122 		this.componentName=component.getComponentName();
123 		this.componentConfiguration=component;
124 		init();
125 	}
126 
127 	/***
128 	 * Loads and wraps a ComponentConfiguration
129 	 * @param componentName
130 	 */
131 	public ComponentConfigurationDynamicMBean(String componentName) {
132 		super();
133 		this.componentName = componentName;
134 		this.componentConfiguration = EasyConf.getConfiguration(componentName);
135 		init();		
136 	}
137 
138 	/***
139 	 * Some initializations common to both constructors
140 	 */
141 	private void init(){
142 		this.modifiedProperties = new HashMap();
143 		this.newPropeties = new HashMap();
144 	}
145 
146 	/***
147 	 * Obtains the component attributes from the ComponentCongiguration
148 	 * 
149 	 * @see javax.management.DynamicMBean#getAttribute(java.lang.String)
150 	 */
151 	public Object getAttribute(String attributeName)
152 			throws AttributeNotFoundException, MBeanException,
153 			ReflectionException {
154 		ComponentProperties prop = componentConfiguration.getProperties();
155 		if (modifiedProperties.containsKey(attributeName))
156 			return modifiedProperties.get(attributeName);
157 		if (prop.containsKey(attributeName))
158 			return prop.getProperty(attributeName);
159 		else if (newPropeties.containsKey(attributeName))
160 			return newPropeties.get(attributeName);
161 		else
162 			throw new AttributeNotFoundException(attributeName);
163 	}
164 
165 	/***
166 	 * Sets an attribute
167 	 * 
168 	 * @see javax.management.DynamicMBean#setAttribute(javax.management.Attribute)
169 	 */
170 	public void setAttribute(Attribute attribute)
171 			throws AttributeNotFoundException, InvalidAttributeValueException,
172 			MBeanException, ReflectionException {
173 		if (componentConfiguration.getProperties().containsKey(
174 				attribute.getName()))
175 			modifiedProperties.put(attribute.getName(), attribute.getValue());
176 		else if (newPropeties.containsKey(attribute.getName()))
177 			newPropeties.put(attribute.getName(), attribute.getValue());
178 		else
179 			throw new AttributeNotFoundException(attribute.getName());
180 	}
181 
182 	/***
183 	 * List named attributes
184 	 * 
185 	 * @see javax.management.DynamicMBean#getAttributes(java.lang.String[])
186 	 */
187 	public AttributeList getAttributes(String[] attributesNames) {
188 		Set includedAttributeNames = new HashSet();
189 		AttributeList attributeList = new AttributeList();
190 		for (int i = 0; i < attributesNames.length; i++) {
191 			String attributeName = attributesNames[i];
192 			if (!includedAttributeNames.contains(attributeName)) {
193 				includedAttributeNames.add(attributeName);
194 				try {
195 					Object value = getAttribute(attributeName);
196 					Attribute attribute = new Attribute(attributeName, value);
197 					attributeList.add(attribute);
198 				} catch (AttributeNotFoundException e) {
199 					// Ignoring attribute
200 				} catch (MBeanException e) {
201 				} catch (ReflectionException e) {
202 				}
203 			}
204 		}
205 		return attributeList;
206 	}
207 
208 	/***
209 	 * Set named attributes
210 	 * 
211 	 * @see javax.management.DynamicMBean#setAttributes(javax.management.AttributeList)
212 	 */
213 	public AttributeList setAttributes(AttributeList attributes) {
214 		AttributeList modifieds = new AttributeList();
215 		Iterator it = attributes.iterator();
216 		while (it.hasNext()) {
217 			Attribute attribute = (Attribute) it.next();
218 			try {
219 				setAttribute(attribute);
220 				modifieds.add(attribute);
221 			} catch (AttributeNotFoundException e) {
222 			} catch (InvalidAttributeValueException e) {
223 			} catch (MBeanException e) {
224 			} catch (ReflectionException e) {
225 			}
226 		}
227 		return modifieds;
228 	}
229 
230 	/***
231 	 * Invoke one of the operations exposed by the MBeanas. 
232 	 * This Operations could be one of:
233 	 * <ul>
234 	 *   <li><code>void newProperty(String propertyName)</code></li>
235 	 *   <li>
236 	 *   	<code>void newProperty(String propertyName, String initialValue)
237 	 *   	</code>
238 	 *   </li>
239 	 *   <li><code>void reloadConfiguration()</code></li>
240 	 * </ul>
241 	 * 
242 	 * @see javax.management.DynamicMBean#invoke(java.lang.String,
243 	 *      java.lang.Object[], java.lang.String[])
244 	 */
245 	public Object invoke(String operationName, Object[] params,
246 			String[] signature) throws MBeanException, ReflectionException {
247 		if (operationName.equals(RELOAD_OPERATION_NAME)) {
248 			reloadConfiguration();
249 			return null;
250 		}
251 		if (operationName.equals(NEW_PROPERTY_OPERATION_NAME)) {
252 			if (signature.length == 1)
253 				newProperty((String) params[0]);
254 			else if (signature.length == 2)
255 				newProperty((String) params[0], params[1]);
256 			else
257 				throw new MBeanException(new IllegalArgumentException(
258 						"Operation not found in MBEan: " + operationName + "("
259 								+ signature + ")"));
260 			return null;
261 		}
262 		throw new MBeanException(new IllegalArgumentException(
263 				"Operation not found in MBEan: " + operationName + "("
264 						+ signature + ")"));
265 	}
266 
267 	// ***** Implementations of the MBean's operations *****//
268 
269 	private void reloadConfiguration() {
270 //		System.out.println("Old Properties: "+componentConfiguration.getProperties().toMap());
271 		EasyConf.refreshComponent(componentName);
272 		this.componentConfiguration = EasyConf.getConfiguration(componentName);
273 //		System.out.println("New Properties: "+componentConfiguration.getProperties().toMap());
274 	}
275 
276 	private void newProperty(String propertyName) throws MBeanException {
277 		newProperty(propertyName, null);
278 	}
279 
280 	private void newProperty(String propertyName, Object value)
281 			throws MBeanException {
282 		ComponentProperties prop = componentConfiguration.getProperties();
283 		if ((newPropeties.containsKey(propertyName))
284 				|| prop.containsKey(propertyName))
285 			throw new MBeanException(new IllegalArgumentException(
286 					"Cannot add new propert whith name: " + propertyName
287 							+ ". There is a property whith that name yet"));
288 		newPropeties.put(propertyName, value);
289 	}
290 
291 	/***
292 	 * Return the Information exposed by the MBean: Attributes, Operations,
293 	 * Constructors and Notifications.
294 	 * 
295 	 * @see javax.management.DynamicMBean#getMBeanInfo()
296 	 */
297 	public MBeanInfo getMBeanInfo() {
298 		return new MBeanInfo(this.getClass().toString(), "Easyconf component: "
299 				+ this.componentName, getAttributeInfo(),
300 				getConsturctorsInfo(), getOperationInfo(), null);
301 	}
302 
303 	/***
304 	 * Constructs the info of the MBean's attributes.
305 	 * 
306 	 * @return Array of MBeanAttributeInfo
307 	 */
308 	protected MBeanAttributeInfo[] getAttributeInfo() {
309 		if (attributesInfo == null) {
310 			ComponentProperties properties = componentConfiguration
311 					.getProperties();
312 			List auxList = new ArrayList();
313 			Iterator it = properties.getKeys();
314 			while (it.hasNext()) {
315 				String propertyName = (String) it.next();
316 				Object value = properties.getProperty(propertyName);
317 				String type = value.getClass().getName();
318 				boolean isIs = value.getClass().equals(Boolean.class);
319 				MBeanAttributeInfo attributeInfo = new MBeanAttributeInfo(
320 						propertyName, type, "Easyconf " + componentName
321 								+ " component property: " + propertyName, true,
322 						true, isIs);
323 				auxList.add(attributeInfo);
324 				this.attributesInfo = (MBeanAttributeInfo[]) auxList
325 						.toArray(new MBeanAttributeInfo[auxList.size()]);
326 			}
327 		}
328 		return this.attributesInfo;
329 	}
330 
331 	/***
332 	 * Constructs the info of the MBean's operations.
333 	 * 
334 	 * @return Array of MBeanOperationInfo
335 	 */
336 	protected MBeanOperationInfo[] getOperationInfo() {
337 		if (operationInfo == null) {
338 			operationInfo = new MBeanOperationInfo[] {
339 					new MBeanOperationInfo(NEW_PROPERTY_OPERATION_NAME,
340 							NEW_PROPERTY_OPERATION_DESCRIPTION_1,
341 							// Parameters
342 							new MBeanParameterInfo[] { new MBeanParameterInfo(
343 									"propertyName", String.class.getName(),
344 									"Name of the new property") }, void.class
345 									.getName(), MBeanOperationInfo.ACTION),
346 					new MBeanOperationInfo(
347 							NEW_PROPERTY_OPERATION_NAME,
348 							NEW_PROPERTY_OPERATION_DESCRIPTION_2,
349 							// Parameters
350 							new MBeanParameterInfo[] {
351 									new MBeanParameterInfo("propertyName",
352 											String.class.getName(),
353 											"Name of the new property"),
354 									new MBeanParameterInfo("value",
355 											Object.class.getName(),
356 											"Initial value of the new property") },
357 							void.class.getName(), MBeanOperationInfo.ACTION),
358 					new MBeanOperationInfo(RELOAD_OPERATION_NAME,
359 							RELOAD_OPERATION_DESCRIPTION,
360 							// Parameters
361 							new MBeanParameterInfo[] {}, void.class.getName(),
362 							MBeanOperationInfo.ACTION) };
363 
364 		}
365 		return operationInfo;
366 	}
367 
368 	/***
369 	 * Constructs an array of the MBean's constructors.
370 	 * 
371 	 * @return Array of MBeanConstructorInfo
372 	 */
373 	protected MBeanConstructorInfo[] getConsturctorsInfo() {
374 		if (constructorsInfo == null) {
375 			Constructor constructor = null;
376 			try {
377 				constructor = this.getClass().getConstructor(
378 						new Class[] { String.class });
379 			} catch (Exception e) {
380 			}
381 			constructorsInfo = new MBeanConstructorInfo[] { new MBeanConstructorInfo(
382 					CONSTRUCTOR_DESCRIPTION_1, constructor) };
383 		}
384 		return constructorsInfo;
385 	}
386 
387 	/***
388 	 * Returns the ComponentConfiguration associated with this MBean.
389 	 * 
390 	 * @return ComponentConfiguration.
391 	 */
392 	protected ComponentConfiguration getComponentConfiguration() {
393 		return componentConfiguration;
394 	}
395 
396 	/***
397 	 * @param componentConfiguration
398 	 *            The componentConfiguration to set.
399 	 */
400 	protected void setComponentConfiguration(
401 			ComponentConfiguration componentConfiguration) {
402 		this.componentConfiguration = componentConfiguration;
403 	}
404 
405 	private boolean propertyExists(String property) {
406 		if (componentConfiguration.getProperties().containsKey(property))
407 			return true;
408 		if (newPropeties.containsKey(property))
409 			return true;
410 		return false;
411 	}
412 }