/* * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/eplv10.html */ package org.opendaylight.yangtools.yang.model.repo.util; import com.google.common.base.Optional; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory; import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository; import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter; import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation; import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider; import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration; import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry; import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceTransformationException; import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceTransformer; import org.opendaylight.yangtools.yang.model.repo.spi.SchemaTransformerRegistration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AbstractSchemaRepository implements SchemaRepository, SchemaSourceRegistry { private static final Logger LOG = LoggerFactory.getLogger(AbstractSchemaRepository.class); private static final Comparator TRANSFORMER_COST_COMPARATOR = new Comparator() { @Override public int compare(final SchemaTransformerRegistration o1, final SchemaTransformerRegistration o2) { return o1.getInstance().getCost() - o2.getInstance().getCost(); } }; /* * Output-type -> transformer map. Our usage involves knowing the destination type, * so we have to work backwards and find a transformer chain which will get us * to that representation given our available sources. */ private final Multimap, SchemaTransformerRegistration> transformers = HashMultimap.create(); /* * Source identifier -> representation -> provider map. We usually are looking for * a specific representation a source. */ private final Map, AbstractSchemaSourceRegistration>> sources = new HashMap<>(); private static final ListenableFuture> fetchSource(final SourceIdentifier id, final Iterator it) { if (!it.hasNext()) { return Futures.immediateFuture(Optional.absent()); } return Futures.transform(((SchemaSourceProvider)it.next().getProvider()).getSource(id), new AsyncFunction, Optional>() { @Override public ListenableFuture> apply(final Optional input) throws Exception { if (input.isPresent()) { return Futures.immediateFuture(input); } else { return fetchSource(id, it); } } }); } private ListenableFuture> transformSchemaSource(final SourceIdentifier id, final Class representation) { final Multimap, AbstractSchemaSourceRegistration> srcs = sources.get(id); if (srcs.isEmpty()) { return Futures.immediateFailedFuture(new SchemaSourceTransformationException( String.format("No providers producing a representation of %s registered", id))); } final Collection ts = transformers.get(representation); if (ts.isEmpty()) { return Futures.immediateFailedFuture(new SchemaSourceTransformationException( String.format("No transformers producing representation %s registered", representation))); } // Build up the candidate list final List candidates = new ArrayList<>(); for (SchemaTransformerRegistration tr : ts) { final SchemaSourceTransformer t = tr.getInstance(); final Class i = t.getInputRepresentation(); if (srcs.containsKey(i)) { candidates.add(tr); } else { LOG.debug("Provider for {} in {} not found, skipping transfomer {}", id, i, t); } } if (candidates.isEmpty()) { return Futures.immediateFailedFuture(new SchemaSourceTransformationException( String.format("No matching source/transformer pair for source %s representation %s found", id, representation))); } Collections.sort(candidates, TRANSFORMER_COST_COMPARATOR); // return transform(candidates.iterator(), id); return null; } /** * Obtain a SchemaSource is selected representation */ protected ListenableFuture> getSchemaSource(final SourceIdentifier id, final Class representation) { final Multimap, AbstractSchemaSourceRegistration> srcs = sources.get(id); if (srcs == null) { LOG.debug("No providers registered for source {}", id); return Futures.immediateFuture(Optional.absent()); } final Collection candidates = srcs.get(representation); return Futures.transform(AbstractSchemaRepository.fetchSource(id, candidates.iterator()), new AsyncFunction, Optional>() { @Override public ListenableFuture> apply(final Optional input) throws Exception { if (input.isPresent()) { return Futures.immediateFuture(input); } return transformSchemaSource(id, representation); } }); } @Override public SchemaContextFactory createSchemaContextFactory(final SchemaSourceFilter filter) { // TODO Auto-generated method stub return null; } private void addSource(final SourceIdentifier id, final Class rep, final AbstractSchemaSourceRegistration reg) { Multimap, AbstractSchemaSourceRegistration> m = sources.get(id); if (m == null) { m = HashMultimap.create(); sources.put(id, m); } m.put(rep, reg); } private void removeSource(final SourceIdentifier id, final Class rep, final SchemaSourceRegistration reg) { final Multimap, AbstractSchemaSourceRegistration> m = sources.get(id); if (m != null) { m.remove(rep, reg); if (m.isEmpty()) { sources.remove(m); } } } @Override public SchemaSourceRegistration registerSchemaSource( final SourceIdentifier identifier, final SchemaSourceProvider provider, final Class representation) { final AbstractSchemaSourceRegistration ret = new AbstractSchemaSourceRegistration(identifier, provider) { @Override protected void removeRegistration() { removeSource(identifier, representation, this); } }; addSource(identifier, representation, ret); return ret; } @Override public SchemaTransformerRegistration registerSchemaSourceTransformer(final SchemaSourceTransformer transformer) { final SchemaTransformerRegistration ret = new AbstractSchemaTransformerRegistration(transformer) { @Override protected void removeRegistration() { transformers.remove(transformer.getOutputRepresentation(), this); } }; transformers.put(transformer.getOutputRepresentation(), ret); return ret; } }