Fix checkstyle in mdsal-binding-generator-impl
[mdsal.git] / binding / mdsal-binding-generator-impl / src / main / java / org / opendaylight / mdsal / binding / generator / impl / ModuleInfoBackedContext.java
1 /*
2  * Copyright (c) 2014 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.mdsal.binding.generator.impl;
9
10 import com.google.common.util.concurrent.Futures;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.lang.ref.WeakReference;
13 import java.util.Optional;
14 import java.util.concurrent.ConcurrentHashMap;
15 import java.util.concurrent.ConcurrentMap;
16 import org.opendaylight.mdsal.binding.generator.api.ClassLoadingStrategy;
17 import org.opendaylight.mdsal.binding.generator.api.ModuleInfoRegistry;
18 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
19 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
20 import org.opendaylight.yangtools.concepts.ObjectRegistration;
21 import org.opendaylight.yangtools.util.ClassLoaderUtils;
22 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
25 import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
26 import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
27 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
28 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
29 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
30 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
31 import org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaContextResolver;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 public final class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy
36         implements ModuleInfoRegistry, SchemaContextProvider, SchemaSourceProvider<YangTextSchemaSource> {
37
38     private final YangTextSchemaContextResolver ctxResolver = YangTextSchemaContextResolver.create("binding-context");
39
40     private ModuleInfoBackedContext(final ClassLoadingStrategy loadingStrategy) {
41         this.backingLoadingStrategy = loadingStrategy;
42     }
43
44     public static ModuleInfoBackedContext create() {
45         return new ModuleInfoBackedContext(getTCCLClassLoadingStrategy());
46     }
47
48     public static ModuleInfoBackedContext create(final ClassLoadingStrategy loadingStrategy) {
49         return new ModuleInfoBackedContext(loadingStrategy);
50     }
51
52     private static final Logger LOG = LoggerFactory.getLogger(ModuleInfoBackedContext.class);
53
54     private final ConcurrentMap<String, WeakReference<ClassLoader>> packageNameToClassLoader =
55             new ConcurrentHashMap<>();
56     private final ConcurrentMap<SourceIdentifier, YangModuleInfo> sourceIdentifierToModuleInfo =
57             new ConcurrentHashMap<>();
58
59     private final ClassLoadingStrategy backingLoadingStrategy;
60
61     @Override
62     public Class<?> loadClass(final String fullyQualifiedName) throws ClassNotFoundException {
63         final String modulePackageName = BindingReflections.getModelRootPackageName(fullyQualifiedName);
64         final WeakReference<ClassLoader> classLoaderRef = packageNameToClassLoader.get(modulePackageName);
65         if (classLoaderRef != null) {
66             final ClassLoader classLoader = classLoaderRef.get();
67             if (classLoader != null) {
68                 return ClassLoaderUtils.loadClass(classLoader, fullyQualifiedName);
69             }
70         }
71
72         if (backingLoadingStrategy == null) {
73             throw new ClassNotFoundException(fullyQualifiedName);
74         }
75
76         final Class<?> cls = backingLoadingStrategy.loadClass(fullyQualifiedName);
77         if (BindingReflections.isBindingClass(cls)) {
78             resolveModuleInfo(cls);
79         }
80
81         return cls;
82     }
83
84     // TODO finish schema parsing and expose as SchemaService
85     // Unite with current SchemaService
86     // Implement remove ModuleInfo to update SchemaContext
87
88     public Optional<SchemaContext> tryToCreateSchemaContext() {
89         return ctxResolver.getSchemaContext();
90     }
91
92     @SuppressWarnings("checkstyle:illegalCatch")
93     private boolean resolveModuleInfo(final Class<?> cls) {
94         try {
95             return resolveModuleInfo(BindingReflections.getModuleInfo(cls));
96         } catch (Exception e) {
97             throw new IllegalStateException(String.format("Failed to resolve module information for class %s", cls), e);
98         }
99     }
100
101     @SuppressWarnings("checkstyle:illegalCatch")
102     private boolean resolveModuleInfo(final YangModuleInfo moduleInfo) {
103
104         SourceIdentifier identifier = sourceIdentifierFrom(moduleInfo);
105         YangModuleInfo previous = sourceIdentifierToModuleInfo.putIfAbsent(identifier, moduleInfo);
106         ClassLoader moduleClassLoader = moduleInfo.getClass().getClassLoader();
107         try {
108             if (previous == null) {
109                 String modulePackageName = moduleInfo.getClass().getPackage().getName();
110                 packageNameToClassLoader.putIfAbsent(modulePackageName,
111                         new WeakReference<>(moduleClassLoader));
112                 ctxResolver.registerSource(toYangTextSource(identifier, moduleInfo));
113                 for (YangModuleInfo importedInfo : moduleInfo.getImportedModules()) {
114                     resolveModuleInfo(importedInfo);
115                 }
116             } else {
117                 return false;
118             }
119         } catch (Exception e) {
120             LOG.error("Not including {} in YANG sources because of error.", moduleInfo, e);
121         }
122         return true;
123     }
124
125     private static YangTextSchemaSource toYangTextSource(final SourceIdentifier identifier,
126             final YangModuleInfo moduleInfo) {
127         return YangTextSchemaSource.delegateForByteSource(identifier, moduleInfo.getYangTextByteSource());
128     }
129
130     private static SourceIdentifier sourceIdentifierFrom(final YangModuleInfo moduleInfo) {
131         final QName name = moduleInfo.getName();
132         return RevisionSourceIdentifier.create(name.getLocalName(), name.getRevision());
133     }
134
135     public void addModuleInfos(final Iterable<? extends YangModuleInfo> moduleInfos) {
136         for (YangModuleInfo yangModuleInfo : moduleInfos) {
137             registerModuleInfo(yangModuleInfo);
138         }
139     }
140
141     @Override
142     public ObjectRegistration<YangModuleInfo> registerModuleInfo(final YangModuleInfo yangModuleInfo) {
143         YangModuleInfoRegistration registration = new YangModuleInfoRegistration(yangModuleInfo, this);
144         resolveModuleInfo(yangModuleInfo);
145         return registration;
146     }
147
148     @Override
149     public ListenableFuture<? extends YangTextSchemaSource> getSource(
150         final SourceIdentifier sourceIdentifier) {
151         final YangModuleInfo yangModuleInfo = sourceIdentifierToModuleInfo.get(sourceIdentifier);
152
153         if (yangModuleInfo == null) {
154             LOG.debug("Unknown schema source requested: {}, available sources: {}", sourceIdentifier,
155                 sourceIdentifierToModuleInfo.keySet());
156             return Futures.immediateFailedFuture(new SchemaSourceException(
157                 "Unknown schema source: " + sourceIdentifier));
158         }
159
160         return Futures.immediateFuture(YangTextSchemaSource.delegateForByteSource(sourceIdentifier,
161             yangModuleInfo.getYangTextByteSource()));
162     }
163
164     private static class YangModuleInfoRegistration extends AbstractObjectRegistration<YangModuleInfo> {
165
166         private final ModuleInfoBackedContext context;
167
168         YangModuleInfoRegistration(final YangModuleInfo instance, final ModuleInfoBackedContext context) {
169             super(instance);
170             this.context = context;
171         }
172
173         @Override
174         protected void removeRegistration() {
175             context.remove(this);
176         }
177
178     }
179
180     private void remove(final YangModuleInfoRegistration registration) {
181         // FIXME implement
182     }
183
184     @Override
185     public SchemaContext getSchemaContext() {
186         final Optional<SchemaContext> contextOptional = tryToCreateSchemaContext();
187         if (contextOptional.isPresent()) {
188             return contextOptional.get();
189
190         }
191         throw new IllegalStateException("Unable to recreate SchemaContext, error while parsing");
192     }
193 }