/** * Copyright (c) 2007-2012 IBM Corporation 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: * IBM - Initial API and implementation */ package org.eclipse.emf.ecore.resource; import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedMap; import org.eclipse.core.runtime.content.IContentDescriber; import org.eclipse.core.runtime.content.IContentDescription; import org.eclipse.core.runtime.content.IContentType; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.impl.ContentHandlerRegistryImpl; /** * A handler for describing the contents of URIs. * <p> * A content handler is used primarily by a {@link URIConverter URI converter} * which provides support for {@link URIConverter#contentDescription(URI, Map) describing} the contents of a URI * by virtue of having a {@link URIConverter#getContentHandlers() list} of content handlers * that it consults to determine whether the handler {@link #canHandle(URI) can handle} the given URI and if so * that it uses as a delegate for computing the {@link #contentDescription(URI, InputStream, Map, Map) content description}. * </p> * @see URIHandler * @see URIConverter * @since 2.4 */ public interface ContentHandler { /** * A registry of content handlers based on a priority order; lower values indicate have higher priority. */ interface Registry extends SortedMap<Integer, List<ContentHandler>> { /** * A constant indicating a very high priority content handler. */ int VERY_HIGH_PRIORITY = -10000; /** * A constant indicating a high priority content handler. */ int HIGH_PRIORITY = -1000; /** * A constant indicating a normal priority content handler. */ int NORMAL_PRIORITY = 0; /** * A constant indicating a low priority content handler. */ int LOW_PRIORITY = 1000; /** * A constant indicating a very low priority content handler. */ int VERY_LOW_PRIORITY = 10000; /** * Adds an additional content handler with the given priority to the map. * If there is already a list for the given priority in the map, the handler is added to that list. * Otherwise, a new list containing the handler is created and put into the map. * @param priority the priority of the handler. * @param contentHandler the new handler to add. */ void put(int priority, ContentHandler contentHandler); /** * Returns a read only list of all the content handlers in the map in priority order. * @return a read only list of all the content handlers in the map in priority order. */ List<ContentHandler> contentHandlers(); /** * The global static content handler registry instance. */ Registry INSTANCE = new ContentHandlerRegistryImpl(); } /** * Returns whether this handler can describe the contents for the given URI. * @param uri the URI to consider. * @return whether this handler can describe the contents for the given URI. */ boolean canHandle(URI uri); /** * An option used to specify the {@link Set} of properties being requested when computing a {@link #contentDescription(URI, InputStream, Map, Map) content description}. * @see #VALIDITY_PROPERTY * @see #CONTENT_TYPE_PROPERTY * @see #BYTE_ORDER_MARK_PROPERTY * @see #CHARSET_PROPERTY * @see #LINE_DELIMITER_PROPERTY */ String OPTION_REQUESTED_PROPERTIES = "REQUESTED_PROPERTIES"; /** * A {@link #contentDescription(URI, InputStream, Map, Map) content description} property indicating the {@link Validity validity} of the content. * The value will be one of {@link Validity#INVALID}, {@link Validity#INDETERMINATE}, or {@link Validity#VALID}. * This property will always be present in a {@link #contentDescription(URI, InputStream, Map, Map) content description}. * @see Validity * @see IContentDescriber#INVALID * @see IContentDescriber#INDETERMINATE * @see IContentDescriber#VALID */ String VALIDITY_PROPERTY = "org.eclipse.emf.ecore:validity"; /** * A value specifying the validity of a {@link ContentHandler#contentDescription(URI, InputStream, Map, Map) content description}. * The {@link ContentHandler#VALIDITY_PROPERTY validity property} will have a value of this type, * i.., either {@link Validity#INVALID}, {@link Validity#INDETERMINATE}, or {@link Validity#VALID}. * @see IContentDescriber#INVALID * @see IContentDescriber#INDETERMINATE * @see IContentDescriber#VALID */ enum Validity { /** * @see IContentDescriber#INVALID */ INVALID, /** * @see IContentDescriber#INDETERMINATE */ INDETERMINATE, /** * @see IContentDescriber#VALID */ VALID } /** * A {@link #contentDescription(URI, InputStream, Map, Map) content description} property describing the content's type identity. * The value will be an arbitrary string. * The content type is often used to {@link Resource.Factory.Registry#getContentTypeToFactoryMap() determine} an appropriate resource factory * for processing the contents of a URI. * @see IContentType#getId() * @see Resource.Factory.Registry#getContentTypeToFactoryMap() * @see Resource.Factory.Registry#getFactory(URI, String) */ String CONTENT_TYPE_PROPERTY = "org.eclipse.emf.ecore:contentType"; /** * A constant used to indicate that a {@link #CONTENT_TYPE_PROPERTY content type} needs to be computed. * @see ResourceSet#createResource(URI, String) * @see Resource.Factory.Registry#getFactory(URI, String) */ String UNSPECIFIED_CONTENT_TYPE = ""; /** * A {@link #contentDescription(URI, InputStream, Map, Map) content description} property describing the character set encoding used by the bytes of the content. * The value will be a string denoting a character set. * @see IContentDescription#CHARSET */ String CHARSET_PROPERTY = "org.eclipse.core.runtime:charset"; /** * A {@link #contentDescription(URI, InputStream, Map, Map) content description} property describing the line delimiter used by the characters of the content, * as determined from the bytes of the content interpreted using {@link #CHARSET_PROPERTY appropriate character set}. * The value will be a string that can be used as a line delimiter. * @see IContentDescription#CHARSET * @since 2.9 */ String LINE_DELIMITER_PROPERTY = "org.eclipse.emf.ecore:lineDelimiter"; /** * A {@link #contentDescription(URI, InputStream, Map, Map) content description} property describing the byte order mark at the beginning of the contents. * The value will be of type {@link ByteOrderMark}. * @see IContentDescription#BYTE_ORDER_MARK */ String BYTE_ORDER_MARK_PROPERTY = "org.eclipse.core.runtime:bom"; /** * A value specifying the byte order mark of a {@link ContentHandler#contentDescription(URI, InputStream, Map, Map) content description}. * The {@link ContentHandler#BYTE_ORDER_MARK_PROPERTY byte order mark property} will have a value of this type, * i.., either {@link #UTF_8}, {@link #UTF_16BE}, or {@link #UTF_16LE}. * @see IContentDescription#BYTE_ORDER_MARK * @see IContentDescription#BOM_UTF_8 * @see IContentDescription#BOM_UTF_16BE * @see IContentDescription#BOM_UTF_16LE */ enum ByteOrderMark { /** * A byte order mark indicating a UTF-8 encoding. * @see IContentDescription#BOM_UTF_8 */ UTF_8 { @Override public byte[] bytes() { return UTF_8_BYTES; } }, /** * A byte order mark indicating a UTF-16 big endian encoding. * @see IContentDescription#BOM_UTF_16BE */ UTF_16BE { @Override public byte[] bytes() { return UTF_16BE_BYTES; } }, /** * A byte order mark indicating a UTF-16 little endian encoding. * @see IContentDescription#BOM_UTF_16LE */ UTF_16LE { @Override public byte[] bytes() { return UTF_16LE_BYTES; } }; private static final byte [] UTF_8_BYTES; private static final byte [] UTF_16BE_BYTES; private static final byte [] UTF_16LE_BYTES; static { byte [] utf8Bytes; byte [] utf16BEBytes; byte [] utf16LEBytes; try { utf8Bytes = org.eclipse.core.runtime.content.IContentDescription.BOM_UTF_8; utf16BEBytes = org.eclipse.core.runtime.content.IContentDescription.BOM_UTF_16BE; utf16LEBytes = org.eclipse.core.runtime.content.IContentDescription.BOM_UTF_16LE; } catch (Throwable throwable) { utf8Bytes = new byte [] {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}; utf16BEBytes = new byte [] {(byte) 0xFE, (byte) 0xFF}; utf16LEBytes = new byte [] {(byte) 0xFF, (byte) 0xFE}; } UTF_8_BYTES = utf8Bytes; UTF_16BE_BYTES = utf16BEBytes; UTF_16LE_BYTES = utf16LEBytes; } /** * Returns the bytes associated with this byte order mark. * This value will be identical to the corresponding constant for {@link IContentDescription#BYTE_ORDER_MARK}. * @see IContentDescription#BYTE_ORDER_MARK * @see IContentDescription#BOM_UTF_8 * @see IContentDescription#BOM_UTF_16BE * @see IContentDescription#BOM_UTF_16LE * @return the bytes associated with this byte order mark. */ public abstract byte [] bytes(); /** * Returns the byte order mark at the start of the input stream, or <code>null</code> if there isn't one. * @param inputStream the input stream to scan. * @return the byte order mark at the start of the input stream, or <code>null</code> if there isn't one. * @throws IOException if there is a problem reading from the input stream. */ public static ByteOrderMark read(InputStream inputStream) throws IOException { int first = inputStream.read(); if (first == 0xEF) { if (inputStream.read() == 0xBB && inputStream.read() == 0xBF) { return UTF_8; } } else if (first == 0xFE) { if (inputStream.read() == 0xFF) { return UTF_16BE; } } else if (first == 0xFF) { if (inputStream.read() == 0xFE) { return UTF_16LE; } } return null; } } /** * An unmodifiable {@link #contentDescription(URI, InputStream, Map, Map) content description} indicating that the content is invalid. */ Map<String, Object> INVALID_CONTENT_DESCRIPTION = Collections.unmodifiableMap(org.eclipse.emf.ecore.resource.impl.ContentHandlerImpl.createContentDescription(Validity.INVALID)); /** * Returns a map of properties that describe the content of the given URI's corresponding input stream. * The {@link #VALIDITY_PROPERTY validity property} will always be present to indicate the status. * The {@link #CONTENT_TYPE_PROPERTY content type property} too will always be present, * except when the validity property is {@link Validity#INVALID}. * The option {@link #OPTION_REQUESTED_PROPERTIES} can be used to specify the set of additional properties that should appear in the result. * If this option is not present, all properties this handler can compute will be returned. * The context map is used to cache results that can be shared between content handler implementations. * For example, once a content handler has computed the {@link #BYTE_ORDER_MARK_PROPERTY byte order mark property}, * the result can be cached so that it is not recomputed repeatedly. * Similarly, content handlers for XML content might cache the {@link #CONTENT_TYPE_PROPERTY character set property}, * and might even share a parsed XML representation so that each handle can analyze to determine whether that XML is of the expected form for the content type. * * @param uri the URI for which to determine the content description. * @param inputStream the input stream associated with the given URI. * @param options a map of options to direct what kind of description is needed. * @param context a map of contextual information that content handlers use to store partially computed results. * @return a map of properties that describe the content of the given URI's corresponding input stream. * @throws IOException if there is a problem reading the stream. */ Map<String, ?> contentDescription(URI uri, InputStream inputStream, Map<?, ?> options, Map<Object, Object> context) throws IOException; }