Fixed few sonar warnings.
[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.DynamicMBean;
16 import javax.management.InstanceNotFoundException;
17 import javax.management.InvalidAttributeValueException;
18 import javax.management.MBeanException;
19 import javax.management.MBeanOperationInfo;
20 import javax.management.MBeanServer;
21 import javax.management.ObjectName;
22 import javax.management.ReflectionException;
23 import org.opendaylight.controller.config.api.ModuleIdentifier;
24 import org.opendaylight.controller.config.api.ValidationException;
25 import org.opendaylight.controller.config.api.annotations.RequireInterface;
26 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
27 import org.opendaylight.controller.config.spi.Module;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
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 LOG = LoggerFactory
51             .getLogger(DynamicWritableWrapper.class);
52
53     private final ReadOnlyAtomicBoolean configBeanModificationDisabled;
54
55     public DynamicWritableWrapper(Module module,
56                                   ModuleIdentifier moduleIdentifier,
57                                   String transactionIdentifier,
58                                   ReadOnlyAtomicBoolean configBeanModificationDisabled,
59                                   MBeanServer internalServer, MBeanServer configMBeanServer) {
60         super(module, true, moduleIdentifier, ObjectNameUtil
61                         .createTransactionModuleON(transactionIdentifier, 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("validate");
71         } catch (NoSuchMethodException e) {
72             throw new IllegalStateException("No such method exception on " + moduleIdentifier, e);
73         }
74         return new MBeanOperationInfo[]{new MBeanOperationInfo("Validation", validationMethod)};
75     }
76
77     @Override
78     public synchronized void setAttribute(Attribute attribute)
79             throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
80         Attribute newAttribute = attribute;
81         if (configBeanModificationDisabled.get()) {
82             throw new IllegalStateException("Operation is not allowed now");
83         }
84
85         if ("Attribute".equals(newAttribute.getName())) {
86             setAttribute((Attribute) newAttribute.getValue());
87             return;
88         }
89
90         try {
91             if (newAttribute.getValue() instanceof ObjectName) {
92                 newAttribute = fixDependencyAttribute(newAttribute);
93             } else if (newAttribute.getValue() instanceof ObjectName[]) {
94                 newAttribute = fixDependencyListAttribute(newAttribute);
95             }
96
97             internalServer.setAttribute(objectNameInternal, newAttribute);
98         } catch (InstanceNotFoundException e) {
99             throw new MBeanException(e);
100         }
101
102     }
103
104     private Attribute fixDependencyListAttribute(Attribute attribute) {
105         Attribute newAttribute = attribute;
106         AttributeHolder attributeHolder = attributeHolderMap.get(newAttribute.getName());
107         if (attributeHolder.getRequireInterfaceOrNull() != null) {
108             newAttribute = new Attribute(newAttribute.getName(), fixObjectNames((ObjectName[]) newAttribute.getValue()));
109         }
110         return newAttribute;
111     }
112
113     private Attribute fixDependencyAttribute(Attribute attribute) {
114         Attribute newAttribute = attribute;
115         AttributeHolder attributeHolder = attributeHolderMap.get(newAttribute.getName());
116         if (attributeHolder.getRequireInterfaceOrNull() != null) {
117             newAttribute = new Attribute(newAttribute.getName(), fixObjectName((ObjectName) newAttribute.getValue()));
118         } else {
119             newAttribute = new Attribute(newAttribute.getName(), newAttribute.getValue());
120         }
121         return newAttribute;
122     }
123
124     private ObjectName[] fixObjectNames(ObjectName[] dependencies) {
125         int i = 0;
126
127         for (ObjectName dependencyOn : dependencies) {
128             dependencies[i++] = fixObjectName(dependencyOn);
129         }
130
131         return dependencies;
132     }
133
134     @Override
135     public AttributeList setAttributes(AttributeList attributes) {
136         AttributeList result = new AttributeList();
137         for (Object attributeObject : attributes) {
138             Attribute attribute = (Attribute) attributeObject;
139             try {
140                 setAttribute(attribute);
141                 result.add(attribute);
142             } catch (Exception e) {
143                 LOG.warn("Setting attribute {} failed on {}", attribute.getName(), moduleIdentifier, e);
144                 throw new IllegalArgumentException(
145                         "Setting attribute failed - " + attribute.getName()
146                                 + " on " + moduleIdentifier, e);
147             }
148         }
149         return result;
150     }
151
152     @Override
153     public Object invoke(String actionName, Object[] params, String[] signature)
154             throws MBeanException, ReflectionException {
155         if ("validate".equals(actionName)
156                 && (params == null || params.length == 0)
157                 && (signature == null || signature.length == 0)) {
158             try {
159                 validate();
160             } catch (Exception e) {
161
162                 throw new MBeanException(ValidationException.createForSingleException(
163                         moduleIdentifier, e));
164             }
165             return Void.TYPE;
166         }
167         return super.invoke(actionName, params, signature);
168     }
169
170     public void validate() {
171         module.validate();
172     }
173 }