/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.engine.source; import com.google.dart.engine.AnalysisEngine; import com.google.dart.engine.context.AnalysisContext; import com.google.dart.engine.context.AnalysisException; import com.google.dart.engine.internal.context.AnalysisContextImpl; import com.google.dart.engine.sdk.DartSdk; import java.net.URI; /** * Instances of the class {@code SourceFactory} resolve possibly relative URI's against an existing * {@link Source source}. * * @coverage dart.engine.source */ public class SourceFactory { /** * The analysis context that this source factory is associated with. */ private AnalysisContext context; /** * The resolvers used to resolve absolute URI's. */ private UriResolver[] resolvers; /** * The predicate to determine is {@link Source} is local. */ private LocalSourcePredicate localSourcePredicate = LocalSourcePredicate.NOT_SDK; /** * Initialize a newly created source factory. * * @param resolvers the resolvers used to resolve absolute URI's */ public SourceFactory(UriResolver... resolvers) { this.resolvers = resolvers; } /** * Return a source object representing the given absolute URI, or {@code null} if the URI is not a * valid URI or if it is not an absolute URI. * * @param absoluteUri the absolute URI to be resolved * @return a source object representing the absolute URI */ public Source forUri(String absoluteUri) { try { URI uri = new URI(absoluteUri); if (uri.isAbsolute()) { return internalResolveUri(null, uri); } } catch (Exception exception) { AnalysisEngine.getInstance().getLogger().logError( "Could not resolve URI: " + absoluteUri, exception); } return null; } /** * Return a source object representing the given absolute URI, or {@code null} if the URI is not * an absolute URI. * * @param absoluteUri the absolute URI to be resolved * @return a source object representing the absolute URI */ public Source forUri(URI absoluteUri) { if (absoluteUri.isAbsolute()) { try { return internalResolveUri(null, absoluteUri); } catch (AnalysisException exception) { AnalysisEngine.getInstance().getLogger().logError( "Could not resolve URI: " + absoluteUri, exception); } } return null; } /** * Return a source object that is equal to the source object used to obtain the given encoding. * * @param encoding the encoding of a source object * @return a source object that is described by the given encoding * @throws IllegalArgumentException if the argument is not a valid encoding * @see Source#getEncoding() */ public Source fromEncoding(String encoding) { Source source = forUri(encoding); if (source == null) { throw new IllegalArgumentException("Invalid source encoding: " + encoding); } return source; } /** * Return the analysis context that this source factory is associated with. * * @return the analysis context that this source factory is associated with */ public AnalysisContext getContext() { return context; } /** * Return the {@link DartSdk} associated with this {@link SourceFactory}, or {@code null} if there * is no such SDK. * * @return the {@link DartSdk} associated with this {@link SourceFactory}, or {@code null} if * there is no such SDK */ public DartSdk getDartSdk() { for (UriResolver resolver : resolvers) { if (resolver instanceof DartUriResolver) { DartUriResolver dartUriResolver = (DartUriResolver) resolver; return dartUriResolver.getDartSdk(); } } return null; } /** * Determines if the given {@link Source} is local. * * @param source the {@link Source} to analyze * @return {@code true} if the given {@link Source} is local */ public boolean isLocalSource(Source source) { return localSourcePredicate.isLocal(source); } /** * Return a source object representing the URI that results from resolving the given (possibly * relative) contained URI against the URI associated with an existing source object, whether or * not the resulting source exists, or {@code null} if either the contained URI is invalid or if * it cannot be resolved against the source object's URI. * * @param containingSource the source containing the given URI * @param containedUri the (possibly relative) URI to be resolved against the containing source * @return the source representing the contained URI */ public Source resolveUri(Source containingSource, String containedUri) { if (containedUri == null || containedUri.isEmpty()) { return null; } try { // Force the creation of an escaped URI to deal with spaces, etc. return internalResolveUri(containingSource, new URI(containedUri)); } catch (Exception exception) { AnalysisEngine.getInstance().getLogger().logError( "Could not resolve URI (" + containedUri + ") relative to source (" + containingSource.getFullName() + ")", exception); return null; } } /** * Return an absolute URI that represents the given source, or {@code null} if a valid URI cannot * be computed. * * @param source the source to get URI for * @return the absolute URI representing the given source */ public URI restoreUri(Source source) { for (UriResolver resolver : resolvers) { URI uri = resolver.restoreAbsolute(source); if (uri != null) { return uri; } } return null; } /** * Set the analysis context that this source factory is associated with to the given context. * <p> * <b>Note:</b> This method should only be invoked by * {@link AnalysisContextImpl#setSourceFactory(SourceFactory)} and is only public out of * necessity. * * @param context the analysis context that this source factory is associated with */ public void setContext(AnalysisContext context) { this.context = context; } /** * Sets the {@link LocalSourcePredicate}. * * @param localSourcePredicate the predicate to determine is {@link Source} is local */ public void setLocalSourcePredicate(LocalSourcePredicate localSourcePredicate) { this.localSourcePredicate = localSourcePredicate; } /** * Return a source object representing the URI that results from resolving the given (possibly * relative) contained URI against the URI associated with an existing source object, or * {@code null} if the URI could not be resolved. * * @param containingSource the source containing the given URI * @param containedUri the (possibly relative) URI to be resolved against the containing source * @return the source representing the contained URI * @throws AnalysisException if either the contained URI is invalid or if it cannot be resolved * against the source object's URI */ private Source internalResolveUri(Source containingSource, URI containedUri) throws AnalysisException { if (!containedUri.isAbsolute()) { if (containingSource == null) { throw new AnalysisException("Cannot resolve a relative URI without a containing source: " + containedUri); } containedUri = containingSource.resolveRelativeUri(containedUri); } for (UriResolver resolver : resolvers) { Source result = resolver.resolveAbsolute(containedUri); if (result != null) { return result; } } return null; } }