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