/******************************************************************************* * Copyright (c) 2001, 2008 Oracle 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: * Oracle Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jst.jsf.core.internal.region; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.eclipse.jst.jsf.common.dom.ElementDOMAdapter; import org.eclipse.jst.jsf.context.resolver.structureddocument.IDOMContextResolver; import org.eclipse.jst.jsf.context.resolver.structureddocument.IStructuredDocumentContextResolverFactory; import org.eclipse.jst.jsf.context.resolver.structureddocument.ITaglibContextResolver; import org.eclipse.jst.jsf.context.resolver.structureddocument.internal.IStructuredDocumentContextResolverFactory2; import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContext; import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContextFactory; import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion; import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion; import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionCollection; import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; /** * Adapt a region object for DOM element information. Does not implement entire * DOM interface. Object is lazily initialized and not thread-safe. * * @author cbateman * */ public class Region2ElementAdapter extends ElementDOMAdapter { private final RegionProcessorStrategy _regionParser; /** * Create a new adapter for this region. If the region does not contain * enough information to construct a meaningful adapter, it will throw * NoElementException. The adapter is lazily initialized and won't process * the region until the first call to a get method is made. * * @param region * @throws NoElementException */ public Region2ElementAdapter(final ITextRegion region) throws NoElementException { _regionParser = new RegionProcessorStrategy(region); } @Override public Map<String, Region2AttrAdapter> getAttributes() { return _regionParser.getAttributes(); } @Override public String getNamespace() { return _regionParser.getNamespace(); } @Override public String getLocalName() { return _regionParser.getLocalName(); } @Override public String getNodeName() { return _regionParser.getNodeName(); } @Override public String getPrefix() { return _regionParser.getPrefix(); } /** * @return the structured document context */ public IStructuredDocumentContext getDocumentContext() { return _regionParser._context; } /** * @return an ITextRegion containing absolute offset information for this element */ public ITextRegionCollection getTextRegion() { return _regionParser._region; } /** * @return the element */ public Element getElement() { return (Element) _regionParser._node; } private class RegionProcessorStrategy { private final ITextRegionCollection _region; private Map<String, Region2AttrAdapter> _attributes; private Node _node; private IStructuredDocumentContext _context; RegionProcessorStrategy(final ITextRegion region) throws NoElementException { if (!(region instanceof ITextRegionCollection) || ((ITextRegionCollection) region).getFirstRegion() .getType() != DOMRegionContext.XML_TAG_OPEN) { throw new NoElementException( "Region is not a collection with an open tag"); //$NON-NLS-1$ } _region = (ITextRegionCollection) region; _context = IStructuredDocumentContextFactory.INSTANCE.getContext( ((IStructuredDocumentRegion) _region) .getParentDocument(), _region .getStartOffset()); if (_context == null) { throw new NoElementException( "Couldn't acquire structured document context"); //$NON-NLS-1$ } final IDOMContextResolver resolver = IStructuredDocumentContextResolverFactory.INSTANCE .getDOMContextResolver(_context); if (resolver == null) { throw new NoElementException("Couldn't acquire dom resolver"); //$NON-NLS-1$ } _node = resolver.getNode(); if (_node == null) { throw new NoElementException("Couldn't get Node from region"); //$NON-NLS-1$ } } public String getLocalName() { return _node.getLocalName(); } public String getNodeName() { return _node.getNodeName(); } public String getPrefix() { return _node.getPrefix(); } public String getNamespace() { final ITaglibContextResolver tagLibResolver = IStructuredDocumentContextResolverFactory2.INSTANCE .getTaglibContextResolverFromDelegates(_context); if (tagLibResolver != null) { return tagLibResolver.getTagURIForNodeName(_node); } return null; } public Map<String, Region2AttrAdapter> getAttributes() { mapAttributesOnlyOnce(); return Collections.unmodifiableMap(_attributes); } private void mapAttributesOnlyOnce() { // only once if (_attributes != null) return; _attributes = Collections.EMPTY_MAP; final NamedNodeMap attributes = _node.getAttributes(); if (attributes != null) { final int numAttrs = attributes.getLength(); _attributes = new HashMap<String, Region2AttrAdapter>( (int) (numAttrs / 0.75f) + 1, 0.75f); for (int i = 0; i < numAttrs; i++) { final Node nodeAttr = attributes.item(i); Region2AttrAdapter attr = new Region2AttrAdapter( Region2ElementAdapter.this, nodeAttr); _attributes.put(attr.getLocalName(), attr); } } } } /** * Indicates that construction of this adapter failed because an IRegion * didn't have sufficient information (or didn't represent an element at * all) * * @author cbateman * */ public static class NoElementException extends Exception { /** * serializable id */ private static final long serialVersionUID = -4479154049727036580L; private NoElementException(final String reason) { super(reason); } } }