01ebdbdf94d9905999aa536e00152ddd2e79bc47
[controller.git] / opendaylight / config / config-manager / src / main / java / org / opendaylight / controller / config / manager / impl / dynamicmbean / DynamicWritableWrapper.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.config.manager.impl.dynamicmbean;
9
10 import java.lang.reflect.Method;
11 import javax.annotation.concurrent.ThreadSafe;
12 import javax.management.Attribute;
13 import javax.management.AttributeList;
14 import javax.management.AttributeNotFoundException;
15 import javax.management.InstanceNotFoundException;
16 import javax.management.InvalidAttributeValueException;
17 import javax.management.MBeanException;
18 import javax.management.MBeanOperationInfo;
19 import javax.management.MBeanServer;
20 import javax.management.ObjectName;
21 import javax.management.ReflectionException;
22 import org.opendaylight.controller.config.api.ModuleIdentifier;
23 import org.opendaylight.controller.config.api.ValidationException;
24 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
25 import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
26 import org.opendaylight.controller.config.spi.Module;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31  * Wraps {@link org.opendaylight.controller.config.spi.Module} instance in a
32  * {@link DynamicMBean} interface. Inspects dependency attributes, identified by
33  * ObjectName getter/setter and {@link RequireInterface} annotation. Used to
34  * simplify client calls - to set a dependency, only instance name is needed.
35  * This class creates new writable String attribute for each dependency with
36  * 'Name' suffix backed by the actual ObjectName attribute.
37  * <p>
38  * Thread safety - setting attributes is synchronized on 'this'. Synchronization
39  * of {@link org.opendaylight.controller.config.spi.Module#validate()} and
40  * {@link org.opendaylight.controller.config.spi.Module#getInstance()} is also
41  * guaranteed by
42  * {@link org.opendaylight.controller.config.manager.impl.ConfigTransactionControllerInternal}
43  * so the actual {@link org.opendaylight.controller.config.spi.Module} needs not
44  * to be thread safe.
45  * </p>
46  */
47 @ThreadSafe
48 public class DynamicWritableWrapper extends AbstractDynamicWrapper {
49     private static final Logger LOG = LoggerFactory
50             .getLogger(DynamicWritableWrapper.class);
51
52     private final ReadOnlyAtomicBoolean configBeanModificationDisabled;
53
54     public DynamicWritableWrapper(Module module,
55                                   ModuleIdentifier moduleIdentifier,
56                                   TransactionIdentifier transactionIdentifier,
57                                   ReadOnlyAtomicBoolean configBeanModificationDisabled,
58                                   MBeanServer internalServer, MBeanServer configMBeanServer) {
59         super(module, true, moduleIdentifier, ObjectNameUtil
60                         .createTransactionModuleON(transactionIdentifier.getName(), moduleIdentifier), getOperations(moduleIdentifier),
61                 internalServer, configMBeanServer);
62         this.configBeanModificationDisabled = configBeanModificationDisabled;
63     }
64
65     private static MBeanOperationInfo[] getOperations(
66             ModuleIdentifier moduleIdentifier) {
67         Method validationMethod;
68         try {
69             validationMethod = DynamicWritableWrapper.class.getMethod("validate");
70         } catch (NoSuchMethodException e) {
71             throw new IllegalStateException("No such method exception on " + moduleIdentifier, e);
72         }
73         return new MBeanOperationInfo[]{new MBeanOperationInfo("Validation", validationMethod)};
74     }
75
76     @Override
77     public synchronized void setAttribute(Attribute attribute)
78             throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
79         Attribute newAttribute = attribute;
80         if (configBeanModificationDisabled.get() == true) {
81             throw new IllegalStateException("Operation is not allowed now");
82         }
83
84         if ("Attribute".equals(newAttribute.getName())) {
85             setAttribute((Attribute) newAttribute.getValue());
86             return;
87         }
88
89         try {
90             if (newAttribute.getValue() instanceof ObjectName) {
91                 newAttribute = fixDependencyAttribute(newAttribute);
92             } else if (newAttribute.getValue() instanceof ObjectName[]) {
93                 newAttribute = fixDependencyListAttribute(newAttribute);
94             }
95
96             internalServer.setAttribute(objectNameInternal, newAttribute);
97         } catch (InstanceNotFoundException e) {
98             throw new MBeanException(e);
99         }
100
101     }
102
103     private Attribute fixDependencyListAttribute(Attribute attribute) {
104         Attribute newAttribute = attribute;
105         AttributeHolder attributeHolder = attributeHolderMap.get(newAttribute.getName());
106         if (attributeHolder.getRequireInterfaceOrNull() != null) {
107             newAttribute = new Attribute(newAttribute.getName(), fixObjectNames((ObjectName[]) newAttribute.getValue()));
108         }
109         return newAttribute;
110     }
111
112     private Attribute fixDependencyAttribute(Attribute attribute) {
113         Attribute newAttribute = attribute;
114         AttributeHolder attributeHolder = attributeHolderMap.get(newAttribute.getName());
115         if (attributeHolder.getRequireInterfaceOrNull() != null) {
116             newAttribute = new Attribute(newAttribute.getName(), fixObjectName((ObjectName) newAttribute.getValue()));
117         } else {
118             newAttribute = new Attribute(newAttribute.getName(), newAttribute.getValue());
119         }
120         return newAttribute;
121     }
122
123     private ObjectName[] fixObjectNames(ObjectName[] dependencies) {
124         int i = 0;
125
126         for (ObjectName dependencyOn : dependencies) {
127             dependencies[i++] = fixObjectName(dependencyOn);
128         }
129
130         return dependencies;
131     }
132
133     @Override
134     public AttributeList setAttributes(AttributeList attributes) {
135         AttributeList result = new AttributeList();
136         for (Object attributeObject : attributes) {
137             Attribute attribute = (Attribute) attributeObject;
138             try {
139                 setAttribute(attribute);
140                 result.add(attribute);
141             } catch (Exception e) {
142                 LOG.warn("Setting attribute {} failed on {}", attribute.getName(), moduleIdentifier, e);
143                 throw new IllegalArgumentException(
144                         "Setting attribute failed - " + attribute.getName()
145                                 + " on " + moduleIdentifier, e);
146             }
147         }
148         return result;
149     }
150
151     @Override
152     public Object invoke(String actionName, Object[] params, String[] signature)
153             throws MBeanException, ReflectionException {
154         if ("validate".equals(actionName)
155                 && (params == null || params.length == 0)
156                 && (signature == null || signature.length == 0)) {
157             try {
158                 validate();
159             } catch (Exception e) {
160
161                 throw new MBeanException(ValidationException.createForSingleException(
162                         moduleIdentifier, e));
163             }
164             return Void.TYPE;
165         }
166         return super.invoke(actionName, params, signature);
167     }
168
169     public void validate() {
170         module.validate();
171     }
172 }