Merge "BUG-2288: DOMNotification API"
[controller.git] / opendaylight / config / yang-jmx-generator / src / main / java / org / opendaylight / controller / config / yangjmxgenerator / ServiceInterfaceEntry.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.yangjmxgenerator;
9
10 import static com.google.common.base.Preconditions.checkNotNull;
11 import static java.lang.String.format;
12 import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.SERVICE_TYPE_Q_NAME;
13
14 import com.google.common.base.Optional;
15 import java.util.ArrayList;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.Iterator;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22 import org.opendaylight.yangtools.yang.common.QName;
23 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.Module;
25 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * Represents identity derived from {@link ConfigConstants#SERVICE_TYPE_Q_NAME}.
31  * Example:
32  * <p>
33  * <blockquote>
34  *
35  * <pre>
36  *  identity eventbus {
37  *  description
38  *  "Service representing an event bus. The service acts as message
39  *  router between event producers and event consumers";
40  *
41  *  base "config:service-type";
42  *  config:java-class "com.google.common.eventbus.EventBus";
43  *  }
44  * </pre>
45  *
46  * </blockquote>
47  * </p>
48  */
49 public class ServiceInterfaceEntry extends AbstractEntry {
50     private static final Logger LOG = LoggerFactory
51             .getLogger(ServiceInterfaceEntry.class);
52
53     private static final String CLASS_NAME_SUFFIX = "ServiceInterface";
54     private final Optional<ServiceInterfaceEntry> maybeBaseCache;
55     private final String exportedOsgiClassName;
56     private final QName qName;
57     private final String nullableDescription, packageName, typeName;
58     private final QName yangModuleQName;
59
60     private ServiceInterfaceEntry(IdentitySchemaNode id, String packageName, QName yangModuleQName) {
61         this(Optional.<ServiceInterfaceEntry> absent(), id, packageName, yangModuleQName);
62     }
63
64     private ServiceInterfaceEntry(Optional<ServiceInterfaceEntry> base,
65             IdentitySchemaNode id, String packageName, QName yangModuleQName) {
66         checkNotNull(base);
67         this.maybeBaseCache = base;
68         List<UnknownSchemaNode> unknownSchemaNodes = id.getUnknownSchemaNodes();
69         List<String> exportedOsgiClassNames = new ArrayList<>(
70                 unknownSchemaNodes.size());
71         for (UnknownSchemaNode usn : unknownSchemaNodes) {
72             if (ConfigConstants.JAVA_CLASS_EXTENSION_QNAME.equals(usn
73                     .getNodeType())) {
74                 String localName = usn.getNodeParameter();
75                 exportedOsgiClassNames.add(localName);
76             } else {
77                 throw new IllegalStateException(format(
78                         "Unexpected unknown schema node. Expected %s, got %s",
79                         ConfigConstants.JAVA_CLASS_EXTENSION_QNAME,
80                         usn.getNodeType()));
81             }
82         }
83         if (exportedOsgiClassNames.size() != 1) {
84             throw new IllegalArgumentException(
85                     format("Cannot find one to one mapping from %s to "
86                             + "java class defined by %s language extension in %s",
87                             getClass(),
88                             ConfigConstants.JAVA_CLASS_EXTENSION_QNAME, id));
89         }
90         this.exportedOsgiClassName = exportedOsgiClassNames.get(0);
91         qName = id.getQName();
92         nullableDescription = id.getDescription();
93         typeName = getSimpleName(exportedOsgiClassName) + CLASS_NAME_SUFFIX;
94         this.packageName = packageName;
95         this.yangModuleQName = yangModuleQName;
96     }
97
98     private static final String getSimpleName(String fullyQualifiedName) {
99         int lastDotPosition = fullyQualifiedName.lastIndexOf(".");
100         return fullyQualifiedName.substring(lastDotPosition + 1);
101     }
102
103     public String getNullableDescription() {
104         return nullableDescription;
105     }
106
107     public Optional<ServiceInterfaceEntry> getBase() {
108         return maybeBaseCache;
109     }
110
111     public String getExportedOsgiClassName() {
112         return exportedOsgiClassName;
113     }
114
115     public QName getQName() {
116         return qName;
117     }
118
119     /**
120      * @return Map of QNames as keys and ServiceInterfaceEntry instances as
121      *         values
122      */
123     public static Map<QName, ServiceInterfaceEntry> create(Module currentModule,
124             String packageName,Map<IdentitySchemaNode, ServiceInterfaceEntry> definedSEItracker) {
125         LOG.debug("Generating ServiceInterfaces from {} to package {}",
126                 currentModule.getNamespace(), packageName);
127
128         Map<IdentitySchemaNode, ServiceInterfaceEntry> identitiesToSIs = new HashMap<>();
129         Set<IdentitySchemaNode> notVisited = new HashSet<>(
130                 currentModule.getIdentities());
131         int lastSize = notVisited.size() + 1;
132         while (!notVisited.isEmpty()) {
133             if (notVisited.size() == lastSize) {
134                 LOG.debug(
135                         "Following identities will be ignored while generating ServiceInterfaces, as they are not derived from {} : {}",
136                         SERVICE_TYPE_Q_NAME, notVisited);
137                 break;
138             }
139             lastSize = notVisited.size();
140             for (Iterator<IdentitySchemaNode> iterator = notVisited.iterator(); iterator
141                     .hasNext();) {
142                 IdentitySchemaNode identity = iterator.next();
143                 ServiceInterfaceEntry created = null;
144                 if (identity.getBaseIdentity() == null) {
145                     // this can happen while loading config module, just skip
146                     // the identity
147                     continue;
148                 } else if (identity.getBaseIdentity().getQName()
149                         .equals(SERVICE_TYPE_Q_NAME)) {
150                     // this is a base type
151                     created = new ServiceInterfaceEntry(identity, packageName, ModuleUtil.getQName(currentModule));
152                 } else {
153                     ServiceInterfaceEntry foundBase = definedSEItracker
154                             .get(identity.getBaseIdentity());
155                     // derived type, did we convert the parent?
156                     if (foundBase != null) {
157                         created = new ServiceInterfaceEntry(
158                                 Optional.of(foundBase), identity, packageName, ModuleUtil.getQName(currentModule));
159                     }
160                 }
161
162
163                 if (created != null) {
164                     created.setYangModuleName(currentModule.getName());
165                     // TODO how to get local name
166                     created.setYangModuleLocalname(identity.getQName()
167                             .getLocalName());
168                     identitiesToSIs.put(identity, created);
169                     definedSEItracker.put(identity, created);
170                     iterator.remove();
171                 }
172             }
173         }
174         // create result map
175         Map<QName, ServiceInterfaceEntry> resultMap = new HashMap<>();
176         for (ServiceInterfaceEntry sie : identitiesToSIs.values()) {
177             resultMap.put(sie.getQName(), sie);
178         }
179         LOG.debug("Number of ServiceInterfaces to be generated: {}",
180                 resultMap.size());
181         return resultMap;
182     }
183
184     public String getFullyQualifiedName() {
185         return packageName + "." + typeName;
186     }
187
188     public String getPackageName() {
189         return packageName;
190     }
191
192     public String getTypeName() {
193         return typeName;
194     }
195
196     public QName getYangModuleQName() {
197         return yangModuleQName;
198     }
199
200     @Override
201     public boolean equals(Object o) {
202         if (this == o) {
203             return true;
204         }
205         if (o == null || getClass() != o.getClass()) {
206             return false;
207         }
208
209         ServiceInterfaceEntry that = (ServiceInterfaceEntry) o;
210
211         if (!maybeBaseCache.equals(that.maybeBaseCache)) {
212             return false;
213         }
214         if (!nullableDescription.equals(that.nullableDescription)) {
215             return false;
216         }
217         if (!exportedOsgiClassName.equals(that.exportedOsgiClassName)) {
218             return false;
219         }
220         if (!qName.equals(that.qName)) {
221             return false;
222         }
223         if (!packageName.equals(that.packageName)) {
224             return false;
225         }
226         if (!typeName.equals(that.typeName)) {
227             return false;
228         }
229
230         return true;
231     }
232
233     @Override
234     public int hashCode() {
235         int result = maybeBaseCache.hashCode();
236         result = 31 * result + exportedOsgiClassName.hashCode();
237         result = 31 * result + nullableDescription.hashCode();
238         result = 31 * result + typeName.hashCode();
239         result = 31 * result + packageName.hashCode();
240         result = 31 * result + qName.hashCode();
241         return result;
242     }
243
244     @Override
245     public String toString() {
246         return "ServiceInterfaceEntry{" + "maybeBaseCache=" + maybeBaseCache
247                 + ", qName='" + qName + '\'' + ", fullyQualifiedName='"
248                 + getFullyQualifiedName() + '\'' + ", exportedOsgiClassName="
249                 + exportedOsgiClassName + ", nullableDescription='"
250                 + nullableDescription + '\'' + '}';
251     }
252 }