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