View Javadoc

1    /****************************************************************************
2    * Copyright (c) 2005, 2006, 2007, 2008, 2009 Imola Informatica.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the LGPL License v2.1
5    * which accompanies this distribution, and is available at
6    * http://www.gnu.org/licenses/lgpl.html
7    ****************************************************************************/
8   
9   /*******************************************************************************
10   *  Copyright (c) 2005, 2006, 2007 Imola Informatica.
11   *  All rights reserved. This program and the accompanying materials
12   *  are made available under the terms of the LGPL License v2.1
13   *  which accompanies this distribution, and is available at
14   *  http://www.gnu.org/licenses/lgpl.html
15   *******************************************************************************/
16  
17  package it.imolinfo.jbi4corba.jbi.component.runtime;
18  
19  import it.imolinfo.jbi4corba.Logger;
20  import it.imolinfo.jbi4corba.LoggerFactory;
21  import it.imolinfo.jbi4corba.jbi.Messages;
22  
23  import java.io.BufferedWriter;
24  import java.io.File;
25  import java.io.FileInputStream;
26  import java.io.FileOutputStream;
27  import java.io.FileWriter;
28  import java.io.IOException;
29  import java.io.InputStream;
30  import java.io.OutputStream;
31  import java.util.Collections;
32  import java.util.Enumeration;
33  import java.util.HashMap;
34  import java.util.Iterator;
35  import java.util.Map;
36  import java.util.Properties;
37  
38  import javax.jbi.JBIException;
39  import javax.management.AttributeChangeNotification;
40  import javax.management.InvalidAttributeValueException;
41  import javax.management.ListenerNotFoundException;
42  import javax.management.MBeanException;
43  import javax.management.MBeanNotificationInfo;
44  import javax.management.Notification;
45  import javax.management.NotificationBroadcasterSupport;
46  import javax.management.NotificationEmitter;
47  import javax.management.NotificationFilter;
48  import javax.management.NotificationListener;
49  import javax.management.openmbean.CompositeData;
50  import javax.management.openmbean.CompositeDataSupport;
51  import javax.management.openmbean.CompositeType;
52  import javax.management.openmbean.OpenDataException;
53  import javax.management.openmbean.OpenType;
54  import javax.management.openmbean.SimpleType;
55  import javax.management.openmbean.TabularData;
56  import javax.management.openmbean.TabularDataSupport;
57  import javax.management.openmbean.TabularType;
58  
59  import com.sun.jbi.component.jbiext.KeyStoreUtilClient;
60  import com.sun.jbi.configuration.ConfigPersistence;
61  
62  
63  /**
64   * Runtime configuration MBean, allow configuration to be changed at run-time
65   */
66  @SuppressWarnings("unchecked")
67  public class RuntimeConfiguration implements RuntimeConfigurationMBean,
68      NotificationEmitter {
69      private static final Logger LOG = LoggerFactory
70              .getLogger(RuntimeConfiguration.class);
71      private static final Messages MESSAGES
72              = Messages.getMessages(RuntimeConfiguration.class);
73  
74      // Attribute names
75      public static final String CONFIG_THREADS = "OutboundThreads";
76  
77      // Default values in the absence of configuration settings
78      private static final String DEFAULT_THREADS = "5";
79  
80      // Configuration validation settings    
81      long MIN_THREADS = 1;
82      long MAX_THREADS = 10000;
83      
84          
85      // Configuration file name for application configuration objects
86      private static final String PERSIST_APPLICATION_CONFIG_FILE_NAME = "ApplicationConfigurations.properties";
87  	public static final String PERSIST_APPLICATION_VARIABLE_CONFIG_FILE_NAME = "ApplicationVariables.properties";
88      
89      // Application configuration row fields
90      private static final String APPLICATION_CONFIG_ROW_KEY = "configurationName";
91      //private static final String APPLICATION_CONFIG_PROPERTY_IDL = "Provider_IDL";
92      private static final String APPLICATION_CONFIG_PROPERTY_LOCALIZATION_TYPE = "Localization_Type";
93      private static final String APPLICATION_CONFIG_PROPERTY_EXTENSION_NAME = "Name";
94      private static final String APPLICATION_CONFIG_PROPERTY_ORB = "ORB";
95      
96      // Configuration 
97      private Properties mConfig=new Properties();
98      private String mWorkspaceRoot;
99      private String mConfigSchema;
100     private String mConfigData;
101     
102     // Global application configurations
103 	private Map mAppConfigMap=new HashMap();
104     private CompositeType mAppConfigRowType = null;
105     private TabularType mAppConfigTabularType = null;
106 
107 	public static  CompositeType APPVAR_ROW_TYPE;
108     public static  TabularType APPVAR_TABULAR_TYPE;
109 
110 	 // Application Variables
111     private static final String APP_VAR_NAME = "name";
112     private static final String APP_VAR_VALUE = "value";
113     private static final String APP_VAR_TYPE = "type";
114     private static final String[] APP_VAR_FIELDS = {
115             APP_VAR_NAME,
116             APP_VAR_VALUE,
117             APP_VAR_TYPE
118     };
119 
120 	private static final int APP_VAR_COUNT = APP_VAR_FIELDS.length;    	
121 	
122 	// Application Variables store
123 	private  Map<String, String[]> mAppVarMap = null;	
124 
125 	private KeyStoreUtilClient mKeySupport;
126 
127     // Use delegation to support notification
128     NotificationBroadcasterSupport broadcasterSupport = new NotificationBroadcasterSupport();
129 
130     /** Creates a new instance of InstallerExt */
131 	public RuntimeConfiguration(final String workspaceRoot,String configSchema, String configData) throws JBIException {
132         try {
133             mWorkspaceRoot = workspaceRoot;
134             mConfigSchema = configSchema;
135             mConfigData = configData;
136             
137             LOG.debug("ConfigurationDisplaySchema:"+mConfigSchema);
138             LOG.debug("ConfigurationDisplayData:"+mConfigData);
139             
140             // Load the persisted configuration
141 
142             mConfig = ConfigPersistence.loadConfig(workspaceRoot);
143             mAppConfigMap = loadApplicationConfiguration(workspaceRoot);
144             mAppConfigRowType = createApplicationConfigurationCompositeType();
145             mAppConfigTabularType = createApplicationConfigurationTabularType();
146 			APPVAR_ROW_TYPE = createApplicationVariableCompositeType();
147             APPVAR_TABULAR_TYPE = createApplicationVariableTabularType();
148 			mAppVarMap = loadApplicationVariables(workspaceRoot);
149 
150             
151         }catch(Exception e){
152             //if we have an error we assume we aren't in openesb
153             LOG.debug("unable to load configurations properties we assume we aren't running under OpenESB", new JBIException(MESSAGES.getString("CRB000411_Failed_to_construct_composite_data_structures", e.getLocalizedMessage()), e));
154         }
155     }
156 
157 	RuntimeConfiguration(String workspaceRoot, String configSchema) {
158         mWorkspaceRoot = workspaceRoot;
159         mConfigSchema = configSchema;
160         mConfig = new Properties();
161         mAppConfigMap = new HashMap();
162         //mAppConfigRowType = createApplicationConfigurationCompositeType();
163         //mAppConfigTabularType = createApplicationConfigurationTabularType();                
164     }
165 
166     /**
167      * @return
168      */
169     //@Override
170     public Integer getOutboundThreads() {
171         final String val = mConfig.getProperty(RuntimeConfiguration.CONFIG_THREADS, RuntimeConfiguration.DEFAULT_THREADS);
172 
173         return Integer.valueOf(val);
174     }
175 
176     /**
177      *
178      * @param val 
179      * @throws javax.management.InvalidAttributeValueException 
180      * @throws javax.management.MBeanException 
181      */
182     //@Override
183     public void setOutboundThreads(final Integer val)
184         throws InvalidAttributeValueException, MBeanException {
185         final String attrName = RuntimeConfiguration.CONFIG_THREADS;
186 
187         // Validate the attribute value
188         Integer newVal = null;
189 
190         try {
191             newVal = val;
192         } catch (final Exception ex) {
193             throw new InvalidAttributeValueException(
194                 "Invalid argument for setting attribute " + attrName + " :" +
195                 ex.getMessage());
196         }
197 
198         if ((newVal.intValue() < MIN_THREADS) ||
199                 (newVal.intValue() > MAX_THREADS)) {
200             throw new InvalidAttributeValueException("A value of " + newVal +
201                 " is not valid for attribute " + attrName +
202                 ". The valid range is " + MIN_THREADS + " - " + MAX_THREADS);
203         }
204 
205         // Apply and save the changes
206         mConfig.put(RuntimeConfiguration.CONFIG_THREADS, val.toString());
207         persistConfiguration();
208 
209         // Notify listeners of this change
210         final long seqNo = 0;
211         final String msg = "Attribute changed";
212         final String attrType = Integer.class.getName();
213         final Integer oldVal = getOutboundThreads();
214         final Notification notif = new AttributeChangeNotification(this, seqNo,
215                 System.currentTimeMillis(), msg, attrName, attrType, oldVal,
216                 newVal);
217         broadcasterSupport.sendNotification(notif);
218     }
219 
220     /**
221      *
222      * @throws MBeanException
223      */
224     private void persistConfiguration() throws MBeanException {
225         // Persist the changed configuration        
226         try {
227             ConfigPersistence.persistConfig(mWorkspaceRoot, mConfig);
228         } catch (final JBIException ex) {
229             throw new MBeanException(ex,
230                 "Failed to persist configuration to " + mWorkspaceRoot + ": " +
231                 ex.getMessage());
232         }
233     }
234 
235     /**
236      *
237      * @return
238      */
239     public MBeanNotificationInfo[] getNotificationInfo() {
240         return new MBeanNotificationInfo[] {
241             new MBeanNotificationInfo(new String[] {
242                     AttributeChangeNotification.ATTRIBUTE_CHANGE
243                 }, AttributeChangeNotification.class.getName(),
244                 "Attribute changed")
245         };
246     }
247 
248     /**
249      *
250      * @param listener
251      * @param filter
252      * @param handback
253      */
254     public void addNotificationListener(final NotificationListener listener,
255         final NotificationFilter filter, final Object handback) {
256         broadcasterSupport.addNotificationListener(listener, filter, handback);
257     }
258 
259     /**
260      *
261      * @param listener
262      * @throws ListenerNotFoundException
263      */
264     public void removeNotificationListener(final NotificationListener listener)
265         throws ListenerNotFoundException {
266         broadcasterSupport.removeNotificationListener(listener);
267     }
268 
269     /**
270      *
271      * @param listener
272      * @param filter
273      * @param handback
274      * @throws ListenerNotFoundException
275      */
276     //@Override
277     public void removeNotificationListener(final NotificationListener listener,
278         final NotificationFilter filter, final Object handback)
279         throws ListenerNotFoundException {
280         broadcasterSupport.removeNotificationListener(listener, filter, handback);
281     }
282     
283     /**
284       * Get the CompositeType definition for the components application configuration 
285       *
286       * @return the CompositeType for the components application configuration.
287       */
288      public CompositeType queryApplicationConfigurationType() {
289          return mAppConfigRowType;
290      }
291      
292      /**
293       * Add an application configuration. The configuration name is a part of the CompositeData.
294       * The itemName for the configuration name is "configurationName" and the type is SimpleType.STRING
295       *
296       * @param name - configuration name, must match the value of the field "name" in the namedConfig
297       * @param appConfig - application configuration composite 
298       * @throws MBeanException if the application configuration cannot be added.
299       */
300 	public void addApplicationConfiguration(String name, CompositeData appConfig) throws InvalidAttributeValueException, MBeanException {
301         if (mAppConfigMap.containsKey(name)) {
302             throw new MBeanException(new Exception(MESSAGES.getString("CRB000412_Application_config_name_already_exists for ", name)));
303         }
304         
305         CompositeType rowType = appConfig.getCompositeType();
306         if (rowType.keySet().size() != 4) {
307             throw new InvalidAttributeValueException(MESSAGES.getString("CRB000413_Invalid_Item_Size_for_app_config", new Object[] { name, rowType.keySet().size() }));
308         }
309         
310         if (!appConfig.containsKey(APPLICATION_CONFIG_ROW_KEY)) {
311             throw new InvalidAttributeValueException(MESSAGES.getString("CRB000414_Invalid_key_for_composite_data_for_app_config", name));
312         } 
313         
314         String[] appConfigValues = new String[3];
315         //appConfigValues[0] = (String) appConfig.get(APPLICATION_CONFIG_PROPERTY_IDL);
316         appConfigValues[0] = (String) appConfig.get(APPLICATION_CONFIG_PROPERTY_LOCALIZATION_TYPE);
317         appConfigValues[1] = (String) appConfig.get(APPLICATION_CONFIG_PROPERTY_EXTENSION_NAME);
318         appConfigValues[2] = (String) appConfig.get(APPLICATION_CONFIG_PROPERTY_ORB);
319         
320 
321         if ( appConfigValues[0] == null ||appConfigValues[1] == null || appConfigValues[2] == null) {
322             throw new InvalidAttributeValueException(MESSAGES.getString("CRB000415_Invalid_app_config_composite_data_null", name));
323         }
324         
325         if(appConfigValues[2]!=null && !appConfigValues[2].equals("")){
326             if(appConfigValues[2].indexOf("=") < 1){
327                 throw new InvalidAttributeValueException(MESSAGES.getString("CRB000422_Invalid_ORB_value"));
328             }
329         }
330         
331         if(appConfigValues[0]!=null && !appConfigValues[0].equals("")){
332             if(!appConfigValues[0].equals("NameService") && !appConfigValues[0].equals("corbaloc") 
333                     && !appConfigValues[0].equals("corbaname") && !appConfigValues[0].equals("IOR")){
334                 throw new InvalidAttributeValueException(MESSAGES.getString("CRB000424_Unable_to_add_Localization_type"));
335             }
336         }
337         
338     	
339         mAppConfigMap.put(name, appConfigValues);
340         
341         if (LOG.isInfoEnabled()) {
342             LOG.info(MESSAGES.getString("CRB000219_New_application_configuration_added", new Object[] { name, appConfigValues }));
343         }
344         persistApplicationConfigurationObjects();
345         
346     }
347     
348     /**
349       * Delete an application configuration. 
350       *
351       * @param name - identification of the application configuration to be deleted
352       * @throws MBeanException if the configuration cannot be deleted.
353       */
354     public void deleteApplicationConfiguration(String name) throws MBeanException {
355         if (!mAppConfigMap.containsKey(name)) {
356             throw new MBeanException(new Exception(MESSAGES.getString("CRB000216_Application_configuration_does_not_exist_for_delete", name)));
357         }
358         
359         mAppConfigMap.remove(name);
360         if (LOG.isInfoEnabled()) {
361             LOG.info(MESSAGES.getString("CRB000420_Application_configuration_deleted", name));
362         }
363         persistApplicationConfigurationObjects();
364     }
365     
366     /**
367       * Update a application configuration. The configuration name is a part of the CompositeData.
368       * The itemName for the configuration name is "configurationName" and the type is SimpleType.STRING
369       *
370       * @param name - configuration name, must match the value of the field "configurationName" in the appConfig
371       * @param appConfig - application configuration composite
372       * @throws MBeanException if there are errors encountered when updating the configuration.
373       */
374 
375 	public void setApplicationConfiguration(String name, CompositeData appConfig) throws InvalidAttributeValueException, MBeanException {
376         if (!mAppConfigMap.containsKey(name)) {
377             throw new MBeanException(new Exception(MESSAGES.getString("CRB000417_Application_configuration_does_not_exist_for_set", name)));
378         }
379         
380         CompositeType rowType = appConfig.getCompositeType();
381         if (rowType.keySet().size() != 4) {
382             throw new InvalidAttributeValueException(MESSAGES.getString("CRB000413_Invalid_Item_Size_for_app_config", new Object[] { name, rowType.keySet().size() }));
383         }
384         
385         if (!appConfig.containsKey(APPLICATION_CONFIG_ROW_KEY)) {
386             throw new InvalidAttributeValueException(MESSAGES.getString("CRB000413_Invalid_key_for_composite_data_for_app_config", name));
387         } 
388         String[] appConfigValues = new String[3];
389         //appConfigValues[0] = (String) appConfig.get(APPLICATION_CONFIG_PROPERTY_IDL);
390         appConfigValues[0] = (String) appConfig.get(APPLICATION_CONFIG_PROPERTY_LOCALIZATION_TYPE);
391         appConfigValues[1] = (String) appConfig.get(APPLICATION_CONFIG_PROPERTY_EXTENSION_NAME);
392         appConfigValues[2] = (String) appConfig.get(APPLICATION_CONFIG_PROPERTY_ORB);
393         if ( appConfigValues[0] == null ||appConfigValues[1] == null || appConfigValues[2] == null ) {
394             throw new InvalidAttributeValueException(MESSAGES.getString("CRB000415_Invalid_app_config_composite_data_null", name));
395         }
396         if(appConfigValues[2]!=null && !appConfigValues[2].equals("")){
397             if(appConfigValues[2].indexOf("=") < 1){
398                 throw new InvalidAttributeValueException(MESSAGES.getString("CRB000422_Invalid_ORB_value"));
399             }
400         }
401         
402         if(appConfigValues[0]!=null && !appConfigValues[0].equals("")){
403             if(!appConfigValues[0].equals("NameService") && !appConfigValues[0].equals("corbaloc") 
404                     && !appConfigValues[0].equals("corbaname") && !appConfigValues[0].equals("IOR")){
405                 throw new InvalidAttributeValueException(MESSAGES.getString("CRB000424_Unable_to_add_Localization_type"));
406             }
407         }
408         
409         mAppConfigMap.put(name, appConfigValues);
410         if (LOG.isInfoEnabled()) {
411             LOG.info(MESSAGES.getString("CRB000421_Application_configuration_updated", new Object[] { name, appConfigValues }));
412         }
413         persistApplicationConfigurationObjects();
414     }
415     
416     /**
417      * Get a Map of all application configurations for the component.
418      *
419      * @return a TabularData of all the application configurations for a 
420      *         component keyed by the configuration name. 
421      */
422     public TabularData getApplicationConfigurations() {
423         TabularData tabularData = new TabularDataSupport(mAppConfigTabularType);
424         for (Iterator iter = mAppConfigMap.keySet().iterator(); iter.hasNext(); ) { 
425             String name = (String) iter.next();
426             String[] values = (String[]) mAppConfigMap.get(name);
427             Object[] data = new Object[] {name, values[0], values[1], values[2]};
428             
429             try {
430                 CompositeData rowData = new CompositeDataSupport(mAppConfigRowType,
431                                                                  new String[] { APPLICATION_CONFIG_ROW_KEY,
432                                                                  APPLICATION_CONFIG_PROPERTY_LOCALIZATION_TYPE,
433                                                                  APPLICATION_CONFIG_PROPERTY_EXTENSION_NAME,
434                                                                  APPLICATION_CONFIG_PROPERTY_ORB },
435                                                                  data);
436                 
437                 tabularData.put(rowData);
438             } catch (OpenDataException e) {
439                 throw new RuntimeException(MESSAGES.getString("CRB000418_Unable_to_construct_composite_data_for_app_config"), e);
440             }
441         }
442         
443         return tabularData;
444     }
445     
446     public Map retrieveApplicationConfigurationsMap() {
447         return mAppConfigMap;
448     }
449     
450     public void updateApplicationConfigurationsMap(Map appConfigMap) throws MBeanException {
451         mAppConfigMap = appConfigMap;
452         persistApplicationConfigurationObjects();
453     }
454     
455     private CompositeType createApplicationConfigurationCompositeType() throws OpenDataException {
456     	if (mAppConfigRowType != null) {
457     	    return mAppConfigRowType;
458     	}
459     	
460         String[] appConfigRowAttrNames = { APPLICATION_CONFIG_ROW_KEY, 
461                                            APPLICATION_CONFIG_PROPERTY_LOCALIZATION_TYPE,
462                                            APPLICATION_CONFIG_PROPERTY_EXTENSION_NAME,
463                                            APPLICATION_CONFIG_PROPERTY_ORB };
464         String[] appConfigAttrDesc = { "Application Configuration Name", "Corba Localization Type", "Corba Extension Name", "ORB" };
465         OpenType[] appConfigAttrTypes = { SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING };
466         
467         mAppConfigRowType = new CompositeType("AppliationConfigurationObject",
468                                               "Application Configuration Composite Data",
469                                               appConfigRowAttrNames,
470                                               appConfigAttrDesc,
471                                               appConfigAttrTypes);
472         
473         return mAppConfigRowType;
474     }
475     
476     private TabularType createApplicationConfigurationTabularType() throws OpenDataException {
477     	if (mAppConfigTabularType != null) {
478     	    return mAppConfigTabularType;
479     	}
480     	
481     	if (mAppConfigRowType == null) {
482             mAppConfigRowType = createApplicationConfigurationCompositeType();
483         }
484         
485         mAppConfigTabularType = new TabularType("ApplicationConfigurationObjectList",
486                                                 "List of Application Configuration Objects",
487                                                 mAppConfigRowType,
488                                                 new String[] { APPLICATION_CONFIG_ROW_KEY });
489        
490        return mAppConfigTabularType;
491     }
492     
493     private void persistApplicationConfigurationObjects() throws MBeanException {
494         // Persist the changed configuration        
495         try {
496             File appConfigPersistFileName = new File(mWorkspaceRoot, PERSIST_APPLICATION_CONFIG_FILE_NAME);
497             OutputStream os = new FileOutputStream(appConfigPersistFileName);
498             for (Iterator iter = mAppConfigMap.keySet().iterator(); iter.hasNext(); ) {
499                String key = (String) iter.next();
500                String[] value = (String[]) mAppConfigMap.get(key);
501                String prop = (value != null)? key + "=" + value[0] + ";" + value[1] + ";" + 
502                               value[2] + "\n" : key + "=\n";
503                os.write(prop.getBytes());
504                
505             } 
506             os.close();
507         } catch (Exception ex) {
508             throw new MBeanException(ex, "Failed to persist application configuration objects"); 
509             
510         } 
511     }
512     
513     private Map loadApplicationConfiguration(String workspaceRoot) throws JBIException {
514         Properties persistedConfig = new Properties();
515         Map appConfigMap = new HashMap();
516         
517         File appConfigPersistFileName = new File(workspaceRoot, PERSIST_APPLICATION_CONFIG_FILE_NAME);
518         if (!appConfigPersistFileName.exists()) {
519             return appConfigMap;
520         }
521         
522         try {
523             InputStream is = new FileInputStream(appConfigPersistFileName);
524             persistedConfig.load(is);
525             is.close();
526             
527             // load the persisted application configurations in the map
528             for (Enumeration e = persistedConfig.propertyNames(); e.hasMoreElements(); ) {
529                 String name = (String) e.nextElement();
530                 String value = persistedConfig.getProperty(name);
531                 if(value!=null){
532                     String[] values= value.split(";");
533                     // String.split() will truncate trailing empty strings.
534                     // Hence ensure that values array has 3 elements.
535                     String[] finalValues= new String[3];
536                     for(int i=0; i<values.length ; i++){
537                         finalValues[i] = values[i];
538                     }
539                     appConfigMap.put(name, finalValues);
540                     
541                 }else {
542                     appConfigMap.put(name, value);
543                 }
544                 
545             }
546         } catch (Exception ex) {
547             throw new JBIException("Failed to load persisted application objects", ex);
548         }
549         
550         return appConfigMap; 
551     }
552     
553     /**
554      * Retrieves the configuration display schema
555      */
556     public String retrieveConfigurationDisplaySchema()  {
557         return this.mConfigSchema;
558     }
559     
560     /**
561      * Retrieves the configuration display data
562      */
563     public String retrieveConfigurationDisplayData() {
564         return this.mConfigData;
565     }
566     
567     public Map<String, String[]> retrieveApplicationVariablesMap() {
568     	// 20/11/2008: MARCO for the execution outside Glassfish
569     	if (mAppVarMap == null) {
570     		return new HashMap();
571     	}
572         synchronized (mAppVarMap) {
573             return Collections.unmodifiableMap(mAppVarMap);
574         }
575     }
576 
577 	 public int countVariables() {
578 		// 20/11/2008: MARCO for the execution outside Glassfish
579 	    if (mAppVarMap == null) {
580 	    	return 0;
581 	    }
582         synchronized (mAppVarMap) {
583             return mAppVarMap.size();
584         }
585     }
586 
587 	 public void updateApplicationVariablesMap(Map<String, String[]> map)
588             throws MBeanException {
589 	    // 20/11/2008: MARCO for the execution outside Glassfish
590 		if (mAppVarMap == null) {
591 	    		return;
592 		}
593 	
594         synchronized (mAppVarMap) {
595             mAppVarMap.clear();
596             mAppVarMap.putAll(map);
597             persistAppVarConfig();
598         }
599     }
600 
601     /**
602      * This operation adds a new applicationvariable. If a variable already exists with
603      * the same name as that specified then the operation fails.
604      *
605      * @param name   - name of the application variable
606      * @param appVar - this is the application variable compoiste
607      * @throws javax.management.MBeanException
608      *          if an error occurs in adding the application variables to the
609      *          component.
610      */
611     public void addApplicationVariable(String name, CompositeData appVar)
612             throws MBeanException {
613         
614         synchronized (mAppVarMap) {
615             if (mAppVarMap.containsKey(name)) {
616                 throw new MBeanException(new Exception(MESSAGES.getString(
617                         "CRB000442_AppVarNameAlreadyExists",
618                         name)));
619             }
620 
621             CompositeType rowType = appVar.getCompositeType();
622             if (rowType.keySet().size() != APP_VAR_COUNT) {
623                 throw new MBeanException(new InvalidAttributeValueException(
624                         MESSAGES.getString(
625                                 "CRB000443_AppVarRowSizeInvalid",
626                                 new Object[]{name, APP_VAR_COUNT,
627                                         rowType.keySet().size()})));
628             }
629         
630             if (!appVar.containsKey(APP_VAR_NAME)) {
631                 throw new MBeanException(new InvalidAttributeValueException(
632                         MESSAGES.getString(
633                                 "CRB000444_AppVarMissingField",
634                                 new Object[] {name, APP_VAR_NAME})));
635             }
636             String appVarName = (String) appVar.get(APP_VAR_NAME);
637             if (!appVarName.equals(name)) {
638                 throw new MBeanException(new InvalidAttributeValueException(
639                         MESSAGES.getString(
640                                 "CRB000448_AppVarNameMismatch",
641                                 new Object[] {name, appVarName})));
642             }
643 
644             String appVarValue = (String) appVar.get(APP_VAR_VALUE);
645             if (appVarValue == null) {
646                 throw new MBeanException(new InvalidAttributeValueException(
647                         MESSAGES.getString(
648                                 "CRB000447_AppVarValueNull",
649                                 new Object[] {name, APP_VAR_VALUE})));
650             }
651         
652             String appVarType = (String) appVar.get(APP_VAR_TYPE);
653             if (appVarType == null) {
654                 throw new MBeanException(new InvalidAttributeValueException(
655                         MESSAGES.getString(
656                                 "CRB000447_AppVarValueNull",
657                                 new Object[] {name, APP_VAR_TYPE})));
658             }
659         
660             mAppVarMap.put(name, new String[] { appVarValue, appVarType });
661             if (LOG.isInfoEnabled()) {
662                 LOG.info(MESSAGES.getString(
663                         "CRB000455_AppVarAdded",
664                         new Object[]{name, appVarValue}));
665             }
666             persistAppVarConfig();
667         }
668     }
669 
670     /**
671      * This operation sets an application variable. If a variable does not exist with
672      * the same name, its an error.
673      *
674      * @param name   - name of the application variable
675      * @param appVar - this is the application variable compoiste to be updated.
676      * @throws javax.management.MBeanException
677      *          if one or more application variables cannot be deleted
678      */
679     public void setApplicationVariable(String name, CompositeData appVar)
680             throws MBeanException {
681         
682         synchronized (mAppVarMap) {
683             if (!mAppVarMap.containsKey(name)) {
684                 throw new MBeanException(new InvalidAttributeValueException(
685                         MESSAGES.getString(
686                                 "CRB000446_AppVarExistenceFailedUpdate",
687                                 name)));
688             }
689         
690             CompositeType rowType = appVar.getCompositeType();
691             if (rowType.keySet().size() != APP_VAR_COUNT) {
692                 throw new MBeanException(new InvalidAttributeValueException(
693                        MESSAGES.getString(
694                                 "CRB000443_AppVarRowSizeInvalid",
695                                 new Object[]{name, APP_VAR_COUNT,
696                                         rowType.keySet().size()})));
697             }
698 
699             if (!appVar.containsKey(APP_VAR_NAME)) {
700                 throw new MBeanException(new InvalidAttributeValueException(
701                         MESSAGES.getString(
702                                 "CRB000444_AppVarMissingField",
703                                 new Object[]{name, APP_VAR_NAME})));
704             } 
705             String appVarName = (String) appVar.get(APP_VAR_NAME);
706             if (!appVarName.equals(name)) {
707                 throw new MBeanException(new InvalidAttributeValueException(
708                         MESSAGES.getString(
709                                 "CRB000448_AppVarNameMismatch",
710                                 new Object[] {name, appVarName})));
711             }
712         
713             String appVarValue = (String)appVar.get(APP_VAR_VALUE);
714             if (appVarValue == null) {
715                 throw new MBeanException(new InvalidAttributeValueException(
716                         MESSAGES.getString(
717                                 "CRB000447_AppVarValueNull",
718                                 new Object[]{name, APP_VAR_VALUE})));
719             }
720         
721             String appVarType = (String)appVar.get(APP_VAR_TYPE);
722             if ( appVarType == null) {
723                 throw new MBeanException(new InvalidAttributeValueException(
724                         MESSAGES.getString(
725                                 "CRB000447_AppVarValueNull",
726                                 new Object[]{name, APP_VAR_TYPE})));
727             }
728         
729             mAppVarMap.put(name, new String[] { appVarValue, appVarType });
730             if (LOG.isInfoEnabled()) {
731                 LOG.info(MESSAGES.getString(
732                         "CRB000450_AppVarUpdated",
733                         new Object[]{name, appVarValue}));
734             }
735             persistAppVarConfig();
736         }
737     }
738 
739     /**
740      * This operation deletes an application variable, if a variable with the specified name does
741      * not exist, it's an error.
742      *
743      * @param name - name of the application variable
744      * @throws javax.management.MBeanException
745      *          on errors.
746      */
747     public void deleteApplicationVariable(String name) throws MBeanException {
748         synchronized (mAppVarMap) {
749             if (!mAppVarMap.containsKey(name)) {
750                 throw new MBeanException(new Exception(MESSAGES.getString(
751                         "CRB000445_AppVarExistenceFailedDelete", name)));
752             }
753             mAppVarMap.remove(name);
754             if (LOG.isInfoEnabled()) {
755                 LOG.info(MESSAGES.getString(
756                         "CRB000451_AppVarDeleted", name));
757             }
758             persistAppVarConfig();
759         }
760     }
761 
762     /**
763      * Get the Application Variable set for a component.
764      *
765      * @return a TabularData which has all the applicationvariables set on the component.
766      */
767     public TabularData getApplicationVariables() {
768         TabularData tabularData = new TabularDataSupport(APPVAR_TABULAR_TYPE);
769         
770         synchronized (mAppVarMap) {
771             for (String name : mAppVarMap.keySet()) {
772                 String[] metadata = mAppVarMap.get(name);
773                 
774                 assert(metadata.length == 2);
775                 
776                 Object[] data = new Object[3];
777                 data[2] = metadata[1];
778                 data[1] = "PASSWORD".equals(data[2]) ? "*******" : metadata[0];
779                 data[0] = name;
780                 
781                 try {
782                     CompositeData rowData = new CompositeDataSupport(
783                             APPVAR_ROW_TYPE, APP_VAR_FIELDS, data);
784                     tabularData.put(rowData);
785                 } catch (OpenDataException e) {
786                     throw new RuntimeException(MESSAGES.getString(
787                             "CRB000449_AppVarTabularCreateFailed"), e);
788                 }
789             }
790         }
791         return tabularData;
792     }
793 
794 	    /**
795      * This method is used at construction time to initialize the type
796      * describing the composition of an application variable.  
797      * @throws OpenDataException
798      */
799     private static CompositeType createApplicationVariableCompositeType()
800             throws OpenDataException {
801         String[] appVarRowAttrNames = {
802                 APP_VAR_NAME, APP_VAR_VALUE, APP_VAR_TYPE
803         };
804         String[] appVarRowAttrDesc = {
805                 "Application Variable Name",
806                 "Application Variable Value",
807                 "Application Variable Type"
808         };
809         OpenType[] appVarRowAttrTypes = {
810                 SimpleType.STRING, SimpleType.STRING, SimpleType.STRING
811         };
812 
813         return new CompositeType("ApplicationVariables",
814             "Application Variable Composite Data",
815             appVarRowAttrNames,
816             appVarRowAttrDesc,
817             appVarRowAttrTypes);
818     }
819 
820     /**
821      * This method is used at construction time to initialize tabular type
822      * information for application variables.  It's important
823      * that {@link #createApplicationConfigurationCompositeType()} is called
824      * first before this method.
825      * 
826      * @throws OpenDataException
827      */
828     private static TabularType createApplicationVariableTabularType() throws OpenDataException {
829         return new TabularType("ApplicationVariableList",
830                 "List of Application Variables",
831                 APPVAR_ROW_TYPE,
832                 new String[] { APP_VAR_NAME } );
833     }
834 
835 	    private void persistAppVarConfig() throws MBeanException {
836         try {
837             File file = new File(mWorkspaceRoot, PERSIST_APPLICATION_VARIABLE_CONFIG_FILE_NAME);
838             BufferedWriter writer = new BufferedWriter(new FileWriter(file));
839             synchronized (mAppVarMap) {
840                 for (String key : mAppVarMap.keySet()) {
841                     String[] metadata = mAppVarMap.get(key);
842                     String value = metadata[0];
843                     String type = metadata[1];
844                     if (type.equals("PASSWORD")) {
845                         if (mKeySupport != null) {
846                             value = mKeySupport.encrypt(value);
847                         }
848                     }
849                     String prop = (value != null)
850                             ? key + "=" + value + "{" + type + "}\n"
851                             : key + "={" + type + "}\n";
852                     writer.write(prop);
853                 } 
854                 writer.flush();
855                 writer.close();
856             }
857         } catch (Exception ex) {
858             throw new MBeanException(ex, MESSAGES.getString(
859                     "CRB000452_AppVarPersistWriteFailed",
860                     PERSIST_APPLICATION_VARIABLE_CONFIG_FILE_NAME));
861         } 
862     }
863 
864 	private Map loadApplicationVariables(String workspaceRoot) throws MBeanException {
865         Properties persistedConfig = new Properties();
866         Map<String, String[]> appVarMap = new HashMap<String, String[]>();
867         
868         File file = new File(workspaceRoot, PERSIST_APPLICATION_VARIABLE_CONFIG_FILE_NAME);
869         if (!file.exists()) {
870             return appVarMap;
871         }
872         
873         try {
874             InputStream is = new FileInputStream(file);
875             persistedConfig.load(is);
876             is.close();
877             
878             // load the persisted environment variable configurations in the map
879             for (Enumeration e = persistedConfig.propertyNames(); e.hasMoreElements(); ) {
880                 String name = (String) e.nextElement();
881                 String metadata = persistedConfig.getProperty(name);
882                 int startIndex = metadata.indexOf("{");
883                 String value = (startIndex == 0) ? null : metadata.substring(0, startIndex);
884                 String type = metadata.substring(startIndex + 1, metadata.length() -1);
885                 if (type.equals("PASSWORD")) {
886                     if (mKeySupport != null) {
887                         try {
888                             value = mKeySupport.decrypt(value);
889                         } catch (Exception e1) {
890                             throw new MBeanException(e1, MESSAGES.getString(
891                                     "CRB000453_AppVarLoadDecryptFailed",
892                                     name
893                             ));
894                         }
895                     }
896                 }
897                 appVarMap.put(name, new String[] {value, type});
898             }
899         } catch (IOException ex) {
900             throw new MBeanException(ex, MESSAGES.getString(
901                     "CRB000454_AppVarPersistLoadFailed",
902                     PERSIST_APPLICATION_VARIABLE_CONFIG_FILE_NAME));
903         }
904         
905         return appVarMap;
906     }
907 
908  }