/******************************************************************************* * Copyright (c) 2009, 2010 Fraunhofer IWU 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/epl-v10.html * * Contributors: * Fraunhofer IWU - initial API and implementation *******************************************************************************/ package net.enilink.komma.model.base; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import net.enilink.komma.model.IContentHandler; import net.enilink.komma.model.IURIConverter; import net.enilink.komma.model.IURIHandler; import net.enilink.komma.model.ModelPlugin; import net.enilink.komma.model.eclipse.PlatformResourceURIHandler; import net.enilink.komma.core.URI; /** * A highly functional and extensible URI converter implementation. * <p> * This implementation provides seamless transparent Eclipse integration by * supporting the <code>platform:/resource</code> mechanism both inside of * Eclipse and outside of Eclipse. Furthermore, although the implementation * imports both {@link org.eclipse.core.runtime} and * {@link org.eclipse.core.resources}, and hence requires the Eclipse libraries * at development time, the implementation does <b>not</b> require them at * runtime. Clients of this implementation must be cautious if they wish to * maintain this platform neutral behaviour. * </p> */ public class ExtensibleURIConverter implements IURIConverter { protected List<IURIHandler> uriHandlers; protected List<IContentHandler> contentHandlers; /** * The URI map. */ protected IURIMapRuleSet uriMap; protected static List<IURIHandler> DEFAULT_URI_HANDLERS = Collections .unmodifiableList(Arrays.<IURIHandler> asList( new PlatformResourceURIHandler(), new FileURIHandler(), new URIHandler())); /** * Creates an instance. */ public ExtensibleURIConverter() { this(DEFAULT_URI_HANDLERS, ModelPlugin.getDefault() .getContentHandlerRegistry().getContentHandlers()); } /** * Creates an instance. */ public ExtensibleURIConverter(Collection<IURIHandler> uriHandlers, Collection<IContentHandler> contentHandlers) { getURIHandlers().addAll(uriHandlers); getContentHandlers().addAll(contentHandlers); } public Collection<IURIHandler> getURIHandlers() { if (uriHandlers == null) { uriHandlers = new ArrayList<IURIHandler>(); } return uriHandlers; } public IURIHandler getURIHandler(URI uri) { for (IURIHandler uriHandler : uriHandlers) { if (uriHandler.canHandle(uri)) { return uriHandler; } } throw new RuntimeException("There is no URIHandler to handle " + uri); } public List<IContentHandler> getContentHandlers() { if (contentHandlers == null) { contentHandlers = new ArrayList<IContentHandler>(); } return contentHandlers; } public OutputStream createOutputStream(URI uri) throws IOException { return createOutputStream(uri, null); } static class OptionsMap implements Map<Object, Object> { protected Object key; protected Object value; protected Map<?, ?> options; protected Map<Object, Object> mergedMap; public OptionsMap(Object key, Object value, Map<?, ?> options) { this.options = options == null ? Collections.EMPTY_MAP : options; this.key = key; this.value = value; } protected Map<Object, Object> mergedMap() { if (mergedMap == null) { mergedMap = new LinkedHashMap<Object, Object>(options); mergedMap.put(key, value); } return mergedMap; } public void clear() { throw new UnsupportedOperationException(); } public boolean containsKey(Object key) { return this.key == key || this.key.equals(key) || options.containsKey(key); } public boolean containsValue(Object value) { return this.value == value || options.containsValue(value); } public Set<Map.Entry<Object, Object>> entrySet() { return mergedMap().entrySet(); } public Object get(Object key) { return this.key == key || this.key.equals(key) ? value : options .get(key); } public boolean isEmpty() { return false; } public Set<Object> keySet() { return mergedMap().keySet(); } public Object put(Object key, Object value) { throw new UnsupportedOperationException(); } public void putAll(Map<? extends Object, ? extends Object> t) { throw new UnsupportedOperationException(); } public Object remove(Object key) { throw new UnsupportedOperationException(); } public int size() { return mergedMap().size(); } public Collection<Object> values() { return mergedMap().values(); } @Override public int hashCode() { return mergedMap().hashCode(); } @Override public boolean equals(Object o) { return mergedMap().equals(0); } } public OutputStream createOutputStream(URI uri, Map<?, ?> options) throws IOException { URI normalizedURI = normalize(uri); return getURIHandler(normalizedURI).createOutputStream(normalizedURI, new OptionsMap(OPTION_URI_CONVERTER, this, options)); } public InputStream createInputStream(URI uri) throws IOException { return createInputStream(uri, null); } public InputStream createInputStream(URI uri, Map<?, ?> options) throws IOException { URI normalizedURI = normalize(uri); return getURIHandler(normalizedURI).createInputStream(normalizedURI, new OptionsMap(OPTION_URI_CONVERTER, this, options)); } public void delete(URI uri, Map<?, ?> options) throws IOException { URI normalizedURI = normalize(uri); getURIHandler(normalizedURI).delete(normalizedURI, new OptionsMap(OPTION_URI_CONVERTER, this, options)); } public Map<String, ?> contentDescription(URI uri, Map<?, ?> options) throws IOException { URI normalizedURI = normalize(uri); return getURIHandler(normalizedURI).contentDescription(normalizedURI, new OptionsMap(OPTION_URI_CONVERTER, this, options)); } public boolean exists(URI uri, Map<?, ?> options) { URI normalizedURI = normalize(uri); return getURIHandler(normalizedURI).exists(normalizedURI, new OptionsMap(OPTION_URI_CONVERTER, this, options)); } public Map<String, ?> getAttributes(URI uri, Map<?, ?> options) { URI normalizedURI = normalize(uri); return getURIHandler(normalizedURI).getAttributes(normalizedURI, new OptionsMap(OPTION_URI_CONVERTER, this, options)); } public void setAttributes(URI uri, Map<String, ?> attributes, Map<?, ?> options) throws IOException { URI normalizedURI = normalize(uri); getURIHandler(normalizedURI).setAttributes(normalizedURI, attributes, new OptionsMap(OPTION_URI_CONVERTER, this, options)); } /** * Returns the normalized form of the URI. * <p> * This implementation does precisely and only the * {@link URIConverter#normalize typical} thing. It calls itself recursively * so that mapped chains are followed. * </p> * * @param uri * the URI to normalize. * @return the normalized form. * @see org.eclipse.emf.ecore.plugin.EcorePlugin#getPlatformResourceMap */ public URI normalize(URI uri) { boolean changed; do { URI oldUri = uri; uri = getURIMapRules().map(uri); changed = !oldUri.equals(uri); } while (changed); return uri; } /* * Javadoc copied from interface. */ public IURIMapRuleSet getURIMapRules() { if (uriMap == null) { uriMap = new CompoundURIMapRuleSet(new URIMapRuleSet(), ModelPlugin .getDefault().getURIMap()); } return uriMap; } @Override public void setURIMapRules(IURIMapRuleSet uriMapRules) { this.uriMap = uriMapRules; } }