Refactor OSGi ModuleInfoSnapshot/BindingRuntimeContext
[mdsal.git] / binding / mdsal-binding-runtime-spi / src / main / java / org / opendaylight / binding / runtime / spi / 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.binding.runtime.spi;
9
10 import static com.google.common.base.Preconditions.checkState;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.annotations.Beta;
14 import com.google.common.cache.CacheBuilder;
15 import com.google.common.cache.CacheLoader;
16 import com.google.common.cache.LoadingCache;
17 import com.google.common.collect.ImmutableSet;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import java.util.Optional;
20 import java.util.Set;
21 import org.checkerframework.checker.lock.qual.Holding;
22 import org.eclipse.jdt.annotation.NonNull;
23 import org.opendaylight.binding.runtime.api.BindingRuntimeContext;
24 import org.opendaylight.binding.runtime.api.BindingRuntimeGenerator;
25 import org.opendaylight.binding.runtime.api.ClassLoadingStrategy;
26 import org.opendaylight.binding.runtime.api.DefaultBindingRuntimeContext;
27 import org.opendaylight.yangtools.util.ClassLoaderUtils;
28 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
29 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
30 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextProvider;
31 import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory;
32 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
33 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
34 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
35 import org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaContextResolver;
36
37 @Beta
38 public class ModuleInfoBackedContext extends AbstractModuleInfoTracker implements ClassLoadingStrategy,
39         EffectiveModelContextProvider, SchemaSourceProvider<YangTextSchemaSource> {
40     private static final class WithFallback extends ModuleInfoBackedContext {
41         private final @NonNull ClassLoadingStrategy fallback;
42
43         WithFallback(final YangTextSchemaContextResolver resolver, final ClassLoadingStrategy fallback) {
44             super(resolver);
45             this.fallback = requireNonNull(fallback);
46         }
47
48         @Override
49         Class<?> loadUnknownClass(final String fullyQualifiedName) throws ClassNotFoundException {
50             // We have not found a matching registration, consult the backing strategy
51             final Class<?> cls = fallback.loadClass(fullyQualifiedName);
52             registerImplicitBindingClass(cls);
53             return cls;
54         }
55     }
56
57     private static final LoadingCache<ClassLoadingStrategy,
58         LoadingCache<ImmutableSet<YangModuleInfo>, ModuleInfoBackedContext>> CONTEXT_CACHES = CacheBuilder.newBuilder()
59             .weakKeys().build(new CacheLoader<ClassLoadingStrategy,
60                 LoadingCache<ImmutableSet<YangModuleInfo>, ModuleInfoBackedContext>>() {
61                     @Override
62                     public LoadingCache<ImmutableSet<YangModuleInfo>, ModuleInfoBackedContext> load(
63                             final ClassLoadingStrategy strategy) {
64                         return CacheBuilder.newBuilder().weakValues().build(
65                             new CacheLoader<Set<YangModuleInfo>, ModuleInfoBackedContext>() {
66                                 @Override
67                                 public ModuleInfoBackedContext load(final Set<YangModuleInfo> key) {
68                                     final ModuleInfoBackedContext context = ModuleInfoBackedContext.create(strategy);
69                                     context.registerModuleInfos(key);
70                                     return context;
71                                 }
72                             });
73                     }
74             });
75
76     ModuleInfoBackedContext(final YangTextSchemaContextResolver resolver) {
77         super(resolver);
78     }
79
80     @Beta
81     public static ModuleInfoBackedContext cacheContext(final ClassLoadingStrategy loadingStrategy,
82             final ImmutableSet<YangModuleInfo> infos) {
83         return CONTEXT_CACHES.getUnchecked(loadingStrategy).getUnchecked(infos);
84     }
85
86     public static ModuleInfoBackedContext create() {
87         return create("unnamed");
88     }
89
90     public static ModuleInfoBackedContext create(final String id) {
91         return new ModuleInfoBackedContext(YangTextSchemaContextResolver.create(id));
92     }
93
94     public static ModuleInfoBackedContext create(final ClassLoadingStrategy loadingStrategy) {
95         return create("unnamed", loadingStrategy);
96     }
97
98     public static ModuleInfoBackedContext create(final String id, final ClassLoadingStrategy loadingStrategy) {
99         return new WithFallback(YangTextSchemaContextResolver.create(id), loadingStrategy);
100     }
101
102     public static ModuleInfoBackedContext create(final String id, final YangParserFactory factory) {
103         return new ModuleInfoBackedContext(YangTextSchemaContextResolver.create(id, factory));
104     }
105
106     public static ModuleInfoBackedContext create(final String id, final YangParserFactory factory,
107             final ClassLoadingStrategy loadingStrategy) {
108         return new WithFallback(YangTextSchemaContextResolver.create(id, factory), loadingStrategy);
109     }
110
111     @Override
112     public final EffectiveModelContext getEffectiveModelContext() {
113         final Optional<? extends EffectiveModelContext> contextOptional = tryToCreateModelContext();
114         checkState(contextOptional.isPresent(), "Unable to recreate SchemaContext, error while parsing");
115         return contextOptional.get();
116     }
117
118     @Override
119     public final synchronized Class<?> loadClass(final String fullyQualifiedName) throws ClassNotFoundException {
120         final ClassLoader loader = findClassLoader(fullyQualifiedName);
121         return loader != null ? ClassLoaderUtils.loadClass(loader, fullyQualifiedName)
122                 : loadUnknownClass(fullyQualifiedName);
123     }
124
125     @Override
126     public final ListenableFuture<? extends YangTextSchemaSource> getSource(final SourceIdentifier sourceIdentifier) {
127         return getResolverSource(sourceIdentifier);
128     }
129
130     @Beta
131     public final @NonNull BindingRuntimeContext createRuntimeContext(final BindingRuntimeGenerator generator) {
132         return DefaultBindingRuntimeContext.create(
133             generator.generateTypeMapping(tryToCreateModelContext().orElseThrow()), this);
134     }
135
136     // TODO finish schema parsing and expose as SchemaService
137     // Unite with current SchemaService
138
139     public final Optional<? extends EffectiveModelContext> tryToCreateModelContext() {
140         return getResolverEffectiveModel();
141     }
142
143     @Holding("this")
144     Class<?> loadUnknownClass(final String fullyQualifiedName) throws ClassNotFoundException {
145         throw new ClassNotFoundException(fullyQualifiedName);
146     }
147 }