Merge "Runtime Codec cleanup"
[yangtools.git] / yang / yang-model-util / src / main / java / org / opendaylight / yangtools / yang / model / repo / util / AbstractSchemaRepository.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/eplv10.html
7  */
8 package org.opendaylight.yangtools.yang.model.repo.util;
9
10 import com.google.common.base.Optional;
11 import com.google.common.collect.HashMultimap;
12 import com.google.common.collect.Multimap;
13 import com.google.common.util.concurrent.AsyncFunction;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.Comparator;
21 import java.util.HashMap;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Map;
25
26 import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
27 import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
28 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
29 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
30 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
31 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
32 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
33 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
34 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceTransformationException;
35 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceTransformer;
36 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaTransformerRegistration;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 public class AbstractSchemaRepository implements SchemaRepository, SchemaSourceRegistry {
41     private static final Logger LOG = LoggerFactory.getLogger(AbstractSchemaRepository.class);
42     private static final Comparator<SchemaTransformerRegistration> TRANSFORMER_COST_COMPARATOR = new Comparator<SchemaTransformerRegistration>() {
43         @Override
44         public int compare(final SchemaTransformerRegistration o1, final SchemaTransformerRegistration o2) {
45             return o1.getInstance().getCost() - o2.getInstance().getCost();
46         }
47     };
48
49     /*
50      * Output-type -> transformer map. Our usage involves knowing the destination type,
51      * so we have to work backwards and find a transformer chain which will get us
52      * to that representation given our available sources.
53      */
54     private final Multimap<Class<? extends SchemaSourceRepresentation>, SchemaTransformerRegistration> transformers =
55             HashMultimap.create();
56
57     /*
58      * Source identifier -> representation -> provider map. We usually are looking for
59      * a specific representation a source.
60      */
61     private final Map<SourceIdentifier, Multimap<Class<?>, AbstractSchemaSourceRegistration>> sources = new HashMap<>();
62
63
64     private static final <T extends SchemaSourceRepresentation> ListenableFuture<Optional<T>> fetchSource(final SourceIdentifier id, final Iterator<AbstractSchemaSourceRegistration> it) {
65         if (!it.hasNext()) {
66             return Futures.immediateFuture(Optional.<T>absent());
67         }
68
69         return Futures.transform(((SchemaSourceProvider<T>)it.next().getProvider()).getSource(id), new AsyncFunction<Optional<T>, Optional<T>>() {
70             @Override
71             public ListenableFuture<Optional<T>> apply(final Optional<T> input) throws Exception {
72                 if (input.isPresent()) {
73                     return Futures.immediateFuture(input);
74                 } else {
75                     return fetchSource(id, it);
76                 }
77             }
78         });
79     }
80
81     private <T extends SchemaSourceRepresentation> ListenableFuture<Optional<T>> transformSchemaSource(final SourceIdentifier id, final Class<T> representation) {
82         final Multimap<Class<?>, AbstractSchemaSourceRegistration> srcs = sources.get(id);
83         if (srcs.isEmpty()) {
84             return Futures.immediateFailedFuture(new SchemaSourceTransformationException(
85                     String.format("No providers producing a representation of %s registered", id)));
86         }
87
88         final Collection<SchemaTransformerRegistration> ts = transformers.get(representation);
89         if (ts.isEmpty()) {
90             return Futures.immediateFailedFuture(new SchemaSourceTransformationException(
91                     String.format("No transformers producing representation %s registered", representation)));
92         }
93
94         // Build up the candidate list
95         final List<SchemaTransformerRegistration> candidates = new ArrayList<>();
96         for (SchemaTransformerRegistration tr : ts) {
97             final SchemaSourceTransformer<?, ?> t = tr.getInstance();
98             final Class<?> i = t.getInputRepresentation();
99             if (srcs.containsKey(i)) {
100                 candidates.add(tr);
101             } else {
102                 LOG.debug("Provider for {} in {} not found, skipping transfomer {}", id, i, t);
103             }
104         }
105
106         if (candidates.isEmpty()) {
107             return Futures.immediateFailedFuture(new SchemaSourceTransformationException(
108                     String.format("No matching source/transformer pair for source %s representation %s found", id, representation)));
109         }
110
111         Collections.sort(candidates, TRANSFORMER_COST_COMPARATOR);
112         // return transform(candidates.iterator(), id);
113         return null;
114     }
115
116     /**
117      * Obtain a SchemaSource is selected representation
118      */
119     protected <T extends SchemaSourceRepresentation> ListenableFuture<Optional<T>> getSchemaSource(final SourceIdentifier id, final Class<T> representation) {
120         final Multimap<Class<?>, AbstractSchemaSourceRegistration> srcs = sources.get(id);
121         if (srcs == null) {
122             LOG.debug("No providers registered for source {}", id);
123             return Futures.immediateFuture(Optional.<T>absent());
124         }
125
126         final Collection<AbstractSchemaSourceRegistration> candidates = srcs.get(representation);
127         return Futures.transform(AbstractSchemaRepository.<T>fetchSource(id, candidates.iterator()), new AsyncFunction<Optional<T>, Optional<T>>() {
128             @Override
129             public ListenableFuture<Optional<T>> apply(final Optional<T> input) throws Exception {
130                 if (input.isPresent()) {
131                     return Futures.immediateFuture(input);
132                 }
133
134                 return transformSchemaSource(id, representation);
135             }
136         });
137     }
138
139     @Override
140     public SchemaContextFactory createSchemaContextFactory(final SchemaSourceFilter filter) {
141         // TODO Auto-generated method stub
142         return null;
143     }
144
145     private void addSource(final SourceIdentifier id, final Class<?> rep, final AbstractSchemaSourceRegistration reg) {
146         Multimap<Class<?>, AbstractSchemaSourceRegistration> m = sources.get(id);
147         if (m == null) {
148             m = HashMultimap.create();
149             sources.put(id, m);
150         }
151
152         m.put(rep, reg);
153     }
154
155     private void removeSource(final SourceIdentifier id, final Class<?> rep, final SchemaSourceRegistration reg) {
156         final Multimap<Class<?>, AbstractSchemaSourceRegistration> m = sources.get(id);
157         if (m != null) {
158             m.remove(rep, reg);
159             if (m.isEmpty()) {
160                 sources.remove(m);
161             }
162         }
163     }
164
165     @Override
166     public <T extends SchemaSourceRepresentation> SchemaSourceRegistration registerSchemaSource(
167             final SourceIdentifier identifier, final SchemaSourceProvider<? super T> provider, final Class<T> representation) {
168         final AbstractSchemaSourceRegistration ret = new AbstractSchemaSourceRegistration(identifier, provider) {
169             @Override
170             protected void removeRegistration() {
171                 removeSource(identifier, representation, this);
172             }
173         };
174
175         addSource(identifier, representation, ret);
176         return ret;
177     }
178
179     @Override
180     public SchemaTransformerRegistration registerSchemaSourceTransformer(final SchemaSourceTransformer<?, ?> transformer) {
181         final SchemaTransformerRegistration ret = new AbstractSchemaTransformerRegistration(transformer) {
182             @Override
183             protected void removeRegistration() {
184                 transformers.remove(transformer.getOutputRepresentation(), this);
185             }
186         };
187
188         transformers.put(transformer.getOutputRepresentation(), ret);
189         return ret;
190     }
191 }