| /******************************************************************************* |
| * Copyright (c) 2004-2006 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 Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jst.jsp.core.internal.document; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.content.IContentDescription; |
| import org.eclipse.core.runtime.content.IContentType; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.IDocumentExtension3; |
| import org.eclipse.jface.text.IDocumentPartitioner; |
| import org.eclipse.jst.jsp.core.internal.Logger; |
| import org.eclipse.jst.jsp.core.internal.contentproperties.JSPFContentProperties; |
| import org.eclipse.jst.jsp.core.internal.modelhandler.EmbeddedTypeStateData; |
| import org.eclipse.jst.jsp.core.internal.provisional.contenttype.ContentTypeIdForJSP; |
| import org.eclipse.jst.jsp.core.internal.provisional.contenttype.IContentDescriptionForJSP; |
| import org.eclipse.jst.jsp.core.internal.text.StructuredTextPartitionerForJSP; |
| import org.eclipse.wst.html.core.internal.provisional.contenttype.ContentTypeFamilyForHTML; |
| import org.eclipse.wst.sse.core.internal.ltk.modelhandler.EmbeddedTypeHandler; |
| import org.eclipse.wst.sse.core.internal.modelhandler.EmbeddedTypeRegistry; |
| import org.eclipse.wst.sse.core.internal.modelhandler.EmbeddedTypeRegistryImpl; |
| import org.eclipse.wst.sse.core.internal.provisional.INodeAdapter; |
| import org.eclipse.wst.sse.core.internal.provisional.INodeAdapterFactory; |
| import org.eclipse.wst.sse.core.internal.provisional.INodeNotifier; |
| import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; |
| import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredPartitioning; |
| import org.eclipse.wst.sse.core.internal.util.Debug; |
| import org.eclipse.wst.sse.core.internal.util.DocumentInputStream; |
| import org.eclipse.wst.sse.core.utils.StringUtils; |
| import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode; |
| |
| import com.ibm.icu.util.StringTokenizer; |
| |
| /** |
| * This class has the responsibility to provide an embedded factory registry |
| * for JSP Aware INodeAdapter Factories to use. |
| * |
| * Typically, the embedded type is to be considered a feature of the document, |
| * so JSP Aware AdpaterFactories should call |
| * getAdapter(PageDirectiveAdapter.class) directoy on the document (or owning |
| * document) node. |
| */ |
| public class PageDirectiveAdapterImpl implements PageDirectiveAdapter { |
| |
| protected static final String STR_CHARSET = "charset"; //$NON-NLS-1$ |
| private final static Object adapterType = PageDirectiveAdapter.class; |
| private IStructuredModel model; |
| protected final String[] JAVASCRIPT_LANGUAGE_KEYS = new String[]{"javascript", "javascript1.0", "javascript1.1_3", "javascript1.2", "javascript1.3", "javascript1.4", "javascript1.5", "javascript1.6", "jscript", "sashscript"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ |
| protected final String[] JAVA_LANGUAGE_KEYS = new String[]{"java"}; //$NON-NLS-1$ |
| |
| /** |
| * Constructor for PageDirectiveAdapterImpl. |
| */ |
| public PageDirectiveAdapterImpl(INodeNotifier target) { |
| super(); |
| notifierAtCreation = target; |
| // we need to remember our instance of model, |
| // in case we need to "signal" a re-init needed. |
| if (target instanceof IDOMNode) { |
| IDOMNode node = (IDOMNode) target; |
| model = node.getModel(); |
| } |
| |
| } |
| |
| /** |
| * parses the full contentType value into its two parts the contentType, |
| * and the charset, if present. Note: this method is a lightly modified |
| * version of a method in AbstractHeadParser. There, we're mostly |
| * interested in the charset part of contentTypeValue. Here, we're mostly |
| * interested in the mimeType part. |
| */ |
| private String getMimeTypeFromContentTypeValue(String contentTypeValue) { |
| if (contentTypeValue == null) |
| return null; |
| String cleanContentTypeValue = StringUtils.stripNonLetterDigits(contentTypeValue); |
| StringTokenizer tokenizer = new StringTokenizer(cleanContentTypeValue, ";= \t\n\r\f"); //$NON-NLS-1$ |
| int tLen = tokenizer.countTokens(); |
| // if contains encoding should have three tokens, the mimetype, the |
| // word 'charset', and the encoding value |
| String[] tokens = new String[tLen]; |
| int j = 0; |
| while (tokenizer.hasMoreTokens()) { |
| tokens[j] = tokenizer.nextToken(); |
| j++; |
| } |
| // |
| // Following is the common form for target expression |
| // <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
| // But apparrently is also valid without the content type there, |
| // just the charset, as follows: |
| // <META http-equiv="Content-Type" content="charset=UTF-8"> |
| // So we'll loop through tokens and key off of 'charset' |
| |
| int charsetPos = -1; |
| for (int i = 0; i < tokens.length; i++) { |
| if (tokens[i].equalsIgnoreCase(STR_CHARSET)) { |
| charsetPos = i; |
| break; |
| } |
| } |
| // String charset = null; |
| String contentType = null; |
| if (charsetPos > -1) { |
| // case where charset was present |
| // int charsetValuePos = charsetPos + 1; |
| // if (charsetValuePos < tokens.length) { |
| // charset = tokens[charsetValuePos]; |
| // } |
| int contentTypeValuePos = charsetPos - 1; |
| if (contentTypeValuePos > -1) { |
| contentType = tokens[contentTypeValuePos]; |
| } |
| } |
| else { |
| // charset was not present, so if there's |
| // a value, we assume its the contentType value |
| if (tokens.length > 0) { |
| contentType = tokens[0]; |
| } |
| } |
| return contentType; |
| } |
| |
| private EmbeddedTypeHandler embeddedTypeHandler; |
| private List embeddedFactoryRegistry = new ArrayList(); |
| private String cachedLanguage; |
| private String cachedContentType; |
| private INodeNotifier notifierAtCreation; |
| |
| private int firstLanguagePosition = -1; |
| private int firstContentTypePosition = -1; |
| |
| /* |
| * @see INodeAdapter#isAdapterForType(Object) |
| */ |
| public boolean isAdapterForType(Object type) { |
| return (type == adapterType); |
| } |
| |
| /* |
| * @see INodeAdapter#notifyChanged(INodeNotifier, int, Object, Object, |
| * Object, int) |
| */ |
| public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) { |
| } |
| |
| public void setEmbeddedType(EmbeddedTypeHandler handler) { |
| // if really the same handler, no need for further processing |
| if (embeddedTypeHandler == handler) { |
| return; |
| } |
| // then one exists, and the new one is truely different, so we need to |
| // release and remove current factories |
| if (embeddedTypeHandler != null) { |
| Iterator list = embeddedFactoryRegistry.iterator(); |
| while (list.hasNext()) { |
| INodeAdapterFactory factory = (INodeAdapterFactory) list.next(); |
| factory.release(); |
| } |
| |
| embeddedFactoryRegistry.clear(); |
| } |
| |
| embeddedTypeHandler = handler; |
| // when the handler is set, "transfer" its factories to our own list. |
| // note: our own list may also be added to else where, such as on |
| // "editor side". |
| if (embeddedTypeHandler != null) { |
| Iterator iterator = embeddedTypeHandler.getAdapterFactories().iterator(); |
| while (iterator.hasNext()) { |
| INodeAdapterFactory factory = (INodeAdapterFactory) iterator.next(); |
| embeddedFactoryRegistry.add(factory); |
| } |
| } |
| } |
| |
| /** |
| * @see PageDirectiveAdapter#adapt(INodeNotifier, Object) |
| */ |
| public INodeAdapter adapt(INodeNotifier notifier, Object type) { |
| INodeAdapter result = null; |
| // if embeddedContentType hasn't been set, |
| // then we can not adapt it. |
| if (embeddedTypeHandler != null) { |
| if (embeddedFactoryRegistry != null) { |
| Iterator iterator = embeddedFactoryRegistry.iterator(); |
| INodeAdapterFactory factory = null; |
| while (iterator.hasNext()) { |
| factory = (INodeAdapterFactory) iterator.next(); |
| if (factory.isFactoryForType(type)) { |
| result = factory.adapt(notifier); |
| break; |
| } |
| } |
| } |
| } |
| return result; |
| |
| } |
| |
| /** |
| * @see PageDirectiveAdapter#getEmbeddedType() |
| */ |
| public EmbeddedTypeHandler getEmbeddedType() { |
| if (embeddedTypeHandler == null) { |
| embeddedTypeHandler = getDefaultEmbeddedType(); |
| } |
| return embeddedTypeHandler; |
| } |
| |
| public void addEmbeddedFactory(INodeAdapterFactory factory) { |
| // should we check if already exists in list? |
| embeddedFactoryRegistry.add(factory); |
| } |
| |
| // /** |
| // * Used by PageDirectiveWatchers to signal that some important attribute |
| // has changed, and |
| // * any cached values should be re-calcuated |
| // */ |
| // void changed() { |
| // // we won't actually check if change is needed, if the model state is |
| // already changing. |
| // if (!model.isReinitializationNeeded()) { |
| // // go through our list of page watcher adapters, and updates the |
| // attributes |
| // // we're interested in, if and only if they are the earliest occurance |
| // in the resource |
| // String potentialContentType = null; |
| // String potentialLanguage = null; |
| // int contentTypePosition = -1; |
| // int languagePosition = -1; |
| // Iterator iterator = pageDirectiveWatchers.iterator(); |
| // while (iterator.hasNext()) { |
| // PageDirectiveWatcher pdWatcher = (PageDirectiveWatcher) |
| // iterator.next(); |
| // String contentType = pdWatcher.getContentType(); |
| // String language = pdWatcher.getLanguage(); |
| // int offset = pdWatcher.getOffset(); |
| // if (potentialContentType == null || (hasValue(contentType) && (offset < |
| // contentTypePosition))) { |
| // potentialContentType = contentType; |
| // contentTypePosition = offset; |
| // } |
| // } |
| // // now we have the best candiates for cached values, let's see if |
| // they've really changed from |
| // // what we had. If so, note we go through the setters so side effects |
| // can take place there. |
| // potentialContentType = |
| // getMimeTypeFromContentTypeValue(potentialContentType); |
| // if (potentialContentType == null || potentialContentType.length() == 0) |
| // { |
| // //potentialContentType = getDefaultContentType(); |
| // } else { |
| // setCachedContentType(potentialContentType); |
| // } |
| // |
| // if (potentialLanguage != null && hasValue(potentialLanguage)) { |
| // setCachedLanguage(potentialLanguage); |
| // } |
| // } |
| // } |
| void changedContentType(int elementOffset, String newValue) { |
| // only need to process if this new value is |
| // earlier in the file than our current value |
| if (firstContentTypePosition == -1 || elementOffset <= firstContentTypePosition) { |
| // dw_TODO: update embedded partitioner in JSP document |
| // partitioner |
| // nsd_TODO: update embedded partitioner in JSP document |
| // partitioner |
| |
| // no need to change current value, if we're told some |
| // earlier value is null or blank (sounds like an error, anyway) |
| if (hasValue(newValue)) { |
| firstContentTypePosition = elementOffset; |
| String potentialContentType = getMimeTypeFromContentTypeValue(newValue); |
| // only do the set processing if different |
| // from what it already is |
| // if (!potentialContentType.equalsIgnoreCase(cachedLanguage)) |
| // { |
| setCachedContentType(potentialContentType); |
| // } |
| } |
| } |
| } |
| |
| /** |
| * Used by PageDirectiveWatchers to signal that some important attribute |
| * has changed, and any cached values should be re-calcuated |
| */ |
| void changedLanguage(int elementOffset, String newValue) { |
| // only need to process if this new value is |
| // earlier in the file than our current value |
| // has to be less than or equal to, in case our previous earliest one, |
| // is itself changing! |
| if (firstLanguagePosition == -1 || elementOffset <= firstLanguagePosition) { |
| |
| // no need to change current value, if we're told some |
| // earlier value is null or blank (sounds like an error, anyway) |
| if (hasValue(newValue)) { |
| firstLanguagePosition = elementOffset; |
| // only do the set processing if different |
| // from what it already is |
| if (!newValue.equalsIgnoreCase(cachedLanguage)) { |
| setCachedLanguage(newValue); |
| } |
| } |
| |
| // dw_TODO: set language in document partitioner |
| // nsd_TODO: set language in document partitioner |
| } |
| } |
| |
| /** |
| * Used by PageDirectiveWatchers to signal that some important attribute |
| * has changed, and any cached values should be re-calcuated |
| */ |
| void changedPageEncoding(int elementOffset, String newValue) { |
| |
| // we don't currently track active value, since |
| // just need during read and write (where its |
| // calculated. We will need in future, to |
| // acurately clone a model and to display |
| // "current encoding" to user in status bar. |
| } |
| |
| /** |
| * Method hasValue. |
| * |
| * @param contentType |
| * @return boolean |
| */ |
| private boolean hasValue(String value) { |
| if (value != null && value.length() > 0) |
| return true; |
| else |
| return false; |
| } |
| |
| /** |
| * Returns the cachedContentType. |
| * |
| * @return String |
| */ |
| public String getContentType() { |
| if (cachedContentType == null) { |
| cachedContentType = getDefaultContentType(); |
| } |
| return cachedContentType; |
| } |
| |
| /** |
| * Method getDefaultContentType. |
| * |
| * @return String |
| */ |
| private String getDefaultContentType() { |
| String type = null; |
| IFile file = getFile(model); |
| if (file != null) { |
| type = JSPFContentProperties.getProperty(JSPFContentProperties.JSPCONTENTTYPE, file, true); |
| } |
| // BUG136468 |
| if (type == null) |
| type = "text/html"; //$NON-NLS-1$ |
| return type; |
| } |
| |
| /** |
| * Returns the cachedLanguage. |
| * |
| * @return String |
| */ |
| public String getLanguage() { |
| if (cachedLanguage == null) |
| cachedLanguage = getDefaultLanguage(); |
| return cachedLanguage; |
| } |
| |
| /** |
| * Method getDefaultLanguage. |
| * |
| * @return String |
| */ |
| private String getDefaultLanguage() { |
| String language = null; |
| IFile file = getFile(model); |
| if (file != null) { |
| language = JSPFContentProperties.getProperty(JSPFContentProperties.JSPLANGUAGE, file, true); |
| } |
| // BUG136468 |
| if (language == null) |
| language = "java"; //$NON-NLS-1$ |
| return language; |
| } |
| |
| /** |
| * Sets the cachedContentType. |
| * |
| * @param cachedContentType |
| * The cachedContentType to set |
| */ |
| public void setCachedContentType(String newContentType) { |
| /* |
| * if the passed in value is the same as existing, there's nothing to |
| * do. if its different, then we need to change the contentHandler as |
| * well and, more to the point, signal a re-initializtation is needed. |
| * |
| * Note: if the value we're getting set to does not have a handler in |
| * the registry, we'll actually not set it to null or anything, we'll |
| * just continue on with the one we have. This is pretty important to |
| * avoid re-initializing on every key stroke if someone is typing in a |
| * new content type, but haven't yet finished the whole "word". |
| * However, if an contentType is not recognized, the registry returns |
| * the one for XML. |
| */ |
| |
| /* set the actual value first, the rest is "side effect" */ |
| this.cachedContentType = newContentType; |
| |
| /* see if we need to update embedded handler */ |
| |
| /* |
| * If the document is a type of XHTML, we do not use the page |
| * directive's contentType to determine the embedded type ... its |
| * XHTML! ... and, eventually, the DOCTYPE adapter should determine |
| * if/when it needs to change. |
| */ |
| |
| /* just safety check, can be removed later, early in release cycle */ |
| if (model == null) { |
| // throw IllegalStateException("model should never be null in |
| // PageDirective Adapter"); |
| Logger.log(Logger.ERROR, "model should never be null in PageDirective Adapter"); |
| return; |
| } |
| |
| EmbeddedTypeHandler potentialNewandler = null; |
| IContentDescription contentDescription = getContentDescription(model.getStructuredDocument()); |
| Object prop = contentDescription.getProperty(IContentDescriptionForJSP.CONTENT_FAMILY_ATTRIBUTE); |
| if (prop != null) { |
| if (ContentTypeFamilyForHTML.HTML_FAMILY.equals(prop)) { |
| potentialNewandler = EmbeddedTypeRegistryImpl.getInstance().getTypeFor("text/html"); |
| } |
| } |
| |
| if (potentialNewandler == null) { |
| /* |
| * getHandler should always return something (never null), based |
| * on the rules in the factory. |
| */ |
| potentialNewandler = getHandlerFor(this.cachedContentType); |
| } |
| /* |
| * we do this check for re-init here, instead of in setEmbeddedType, |
| * since setEmbeddedType is called during the normal initializtion |
| * process, when re-init is not needed (since there is no content) |
| */ |
| if (embeddedTypeHandler == null) { |
| setEmbeddedType(potentialNewandler); |
| } |
| else if (potentialNewandler != null && embeddedTypeHandler != potentialNewandler) { |
| /* |
| * changing this embedded handler here may be in the middle of a |
| * notify loop. That's why we set that "it's needed". Then the |
| * model decides when its "safe" to actually do the re-init. |
| * |
| * be sure to hold oldHandler in temp var or else setEmbeddedType |
| * will "reset" it before modelReinitNeeded(oldHandler, handler) |
| * is called |
| * |
| */ |
| EmbeddedTypeHandler oldHandler = embeddedTypeHandler; |
| setEmbeddedType(potentialNewandler); |
| modelReinitNeeded(oldHandler, potentialNewandler); |
| } |
| |
| } |
| |
| /** |
| * This method is used to re-init based on embeddedTypeHandler changing. |
| * It is given priority over the language change, since there its more |
| * important to have old and new handlers's in the stateData field. |
| */ |
| private void modelReinitNeeded(EmbeddedTypeHandler oldHandler, EmbeddedTypeHandler newHandler) { |
| if (model.isReinitializationNeeded()) { |
| System.out.println("already being initialized"); //$NON-NLS-1$ |
| } |
| |
| try { |
| model.aboutToChangeModel(); |
| model.setReinitializeStateData(new EmbeddedTypeStateData(oldHandler, newHandler)); |
| model.setReinitializeNeeded(true); |
| } |
| finally { |
| model.changedModel(); |
| } |
| } |
| |
| /** |
| * Method modelReinitNeeded. |
| */ |
| private void modelReinitNeeded(String oldlanguage, String newLanguage) { |
| // bit of a short cut for now .... we dont' need language at the |
| // moment, |
| // but should set the state data |
| if (model.isReinitializationNeeded()) { |
| if (Debug.displayWarnings) { |
| System.out.println("already being initialized"); //$NON-NLS-1$ |
| } |
| } |
| else { |
| try { |
| // if already being re-initialized, we don't want to |
| // reset the data in the stateData field. |
| model.aboutToChangeModel(); |
| model.setReinitializeStateData(newLanguage); |
| model.setReinitializeNeeded(true); |
| } |
| finally { |
| model.changedModel(); |
| } |
| } |
| } |
| |
| public void setCachedLanguage(String newLanguage) { |
| if (cachedLanguage != null && languageStateChanged(cachedLanguage, newLanguage)) { |
| /* |
| * a complete re-init overkill in current system, since really |
| * just need for the line style providers, BUT, a change in |
| * language could effect other things, and we don't expect to |
| * happen often so a little overkill isn't too bad. The deep |
| * problem is that there is no way to get at the "edit side" |
| * adpapters specifically here in model class. we have to do the |
| * model changed sequence to get the screen to update. do not |
| * signal again, if signaled once (the reinit state data will be |
| * wrong. (this needs to be improved in future) |
| */ |
| if (!model.isReinitializationNeeded()) { |
| modelReinitNeeded(cachedLanguage, newLanguage); |
| } |
| } |
| setLanguage(newLanguage); |
| } |
| |
| /** |
| * This is public access method, used especially from loader, for JSP |
| * Fragment support. |
| */ |
| public void setLanguage(String newLanguage) { |
| this.cachedLanguage = newLanguage; |
| IDocumentPartitioner partitioner = ((IDocumentExtension3) model.getStructuredDocument()).getDocumentPartitioner(IStructuredPartitioning.DEFAULT_STRUCTURED_PARTITIONING); |
| if (partitioner instanceof StructuredTextPartitionerForJSP) { |
| ((StructuredTextPartitionerForJSP) partitioner).setLanguage(newLanguage); |
| } |
| } |
| |
| /** |
| * Method languageStateChange. |
| * |
| * @param cachedLanguage |
| * @param newLanguage |
| * @return boolean |
| */ |
| private boolean languageStateChanged(String cachedLanguage, String newLanguage) { |
| boolean result = false; // languages are equal, then no change in |
| // state |
| if (!cachedLanguage.equalsIgnoreCase(newLanguage)) { |
| boolean oldLanguageKnown = languageKnown(cachedLanguage); |
| boolean newLanguageKnown = languageKnown(newLanguage); |
| result = newLanguageKnown || (!newLanguageKnown && oldLanguageKnown); |
| } |
| return result; |
| } |
| |
| /** |
| * Method languageKnown. |
| * |
| * @param cachedLanguage |
| * @return boolean |
| */ |
| private boolean languageKnown(String language) { |
| return (StringUtils.contains(JAVA_LANGUAGE_KEYS, language, false) || StringUtils.contains(JAVASCRIPT_LANGUAGE_KEYS, language, false)); |
| } |
| |
| private IFile getFile(IStructuredModel model) { |
| String location = model.getBaseLocation(); |
| if (location != null) { |
| IPath path = new Path(location); |
| if (path.segmentCount() > 1) { |
| return ResourcesPlugin.getWorkspace().getRoot().getFile(path); |
| } |
| } |
| return null; |
| } |
| |
| private EmbeddedTypeHandler getHandlerFor(String contentType) { |
| EmbeddedTypeRegistry reg = getEmbeddedContentTypeRegistry(); |
| EmbeddedTypeHandler handler = null; |
| if (reg != null) |
| handler = reg.getTypeFor(contentType); |
| return handler; |
| } |
| |
| /** |
| * Gets the embeddedContentTypeRegistry. |
| * |
| * @return Returns a EmbeddedContentTypeRegistry |
| */ |
| private EmbeddedTypeRegistry getEmbeddedContentTypeRegistry() { |
| return EmbeddedTypeRegistryImpl.getInstance(); |
| } |
| |
| /** |
| * For JSP files, text/html is the default content type. This may want |
| * this different for types like jsv (jsp for voice xml) For now, hard |
| * code to new instance. In future, should get instance from registry. |
| * |
| * Specification cites HTML as the default contentType. |
| */ |
| protected EmbeddedTypeHandler getDefaultEmbeddedType() { |
| return getHandlerFor(getDefaultContentType()); |
| } |
| |
| public INodeNotifier getTarget() { |
| return notifierAtCreation; |
| } |
| |
| public void release() { |
| if (embeddedTypeHandler != null) { |
| if (embeddedFactoryRegistry != null) { |
| Iterator iterator = embeddedFactoryRegistry.iterator(); |
| INodeAdapterFactory factory = null; |
| while (iterator.hasNext()) { |
| factory = (INodeAdapterFactory) iterator.next(); |
| factory.release(); |
| } |
| } |
| // pa_TODO: possibly need to release here... |
| // or "uninitializeFactoryRegistry" |
| // initializeFactoryRegistry was called from JSPModelLoader |
| embeddedTypeHandler = null; |
| } |
| } |
| |
| private IContentDescription getContentDescription(IDocument doc) { |
| if (doc == null) |
| return null; |
| DocumentInputStream in = new DocumentInputStream(doc); |
| return getContentDescription(in); |
| } |
| |
| /** |
| * Returns content description for an input stream Assumes it's JSP |
| * content. Closes the input stream when finished. |
| * |
| * @param in |
| * @return the IContentDescription for in, or null if in is null |
| */ |
| private IContentDescription getContentDescription(DocumentInputStream in) { |
| |
| if (in == null) |
| return null; |
| |
| IContentDescription desc = null; |
| try { |
| |
| IContentType contentTypeJSP = Platform.getContentTypeManager().getContentType(ContentTypeIdForJSP.ContentTypeID_JSP); |
| desc = contentTypeJSP.getDescriptionFor(in, IContentDescription.ALL); |
| } |
| catch (IOException e) { |
| Logger.logException(e); |
| } |
| finally { |
| if (in != null) { |
| try { |
| in.close(); |
| } |
| catch (IOException e) { |
| Logger.logException(e); |
| } |
| } |
| } |
| return desc; |
| } |
| } |