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