Package org.eclipse.jst.jsf.designtime.internal.jsp

Source Code of org.eclipse.jst.jsf.designtime.internal.jsp.JSPModelProcessor$CountingMutex

/*******************************************************************************
* Copyright (c) 2006 Oracle Corporation.
* 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:
*    Cameron Bateman/Oracle - initial API and implementation
*
********************************************************************************/

package org.eclipse.jst.jsf.designtime.internal.jsp;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.ILock;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jst.jsf.common.JSFCommonPlugin;
import org.eclipse.jst.jsf.common.internal.resource.EventResult;
import org.eclipse.jst.jsf.common.internal.resource.IResourceLifecycleListener;
import org.eclipse.jst.jsf.common.internal.resource.LifecycleListener;
import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent;
import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent.EventType;
import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent.ReasonType;
import org.eclipse.jst.jsf.common.metadata.Entity;
import org.eclipse.jst.jsf.common.metadata.Trait;
import org.eclipse.jst.jsf.common.metadata.internal.IMetaDataDomainContext;
import org.eclipse.jst.jsf.common.metadata.internal.TraitValueHelper;
import org.eclipse.jst.jsf.common.metadata.query.internal.MetaDataQueryContextFactory;
import org.eclipse.jst.jsf.common.metadata.query.internal.MetaDataQueryFactory;
import org.eclipse.jst.jsf.common.metadata.query.internal.taglib.ITaglibDomainMetaDataQuery;
import org.eclipse.jst.jsf.context.resolver.structureddocument.IStructuredDocumentContextResolverFactory;
import org.eclipse.jst.jsf.context.resolver.structureddocument.ITaglibContextResolver;
import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContext;
import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContextFactory;
import org.eclipse.jst.jsf.context.symbol.IComponentSymbol;
import org.eclipse.jst.jsf.context.symbol.ISymbol;
import org.eclipse.jst.jsf.context.symbol.SymbolFactory;
import org.eclipse.jst.jsf.context.symbol.source.AbstractContextSymbolFactory;
import org.eclipse.jst.jsf.context.symbol.source.ISymbolConstants;
import org.eclipse.jst.jsf.core.internal.JSFCorePlugin;
import org.eclipse.jst.jsf.designtime.DesignTimeApplicationManager;
import org.eclipse.jst.jsf.designtime.context.DTFacesContext;
import org.eclipse.osgi.util.NLS;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


/**
* Processes a JSP model to determine information of interest about it such
* as what tags are currently in use.  Listens to the model and updates it's
* information when the model changes.
*
* @author cbateman
*
*/
public class JSPModelProcessor
{
    /**
     * Pass to force refresh arguments
     */
    public final static boolean FORCE_REFRESH = true;

    /**
     * Pass to runAfter argument of refresh to indicate there is nothing
     * to run when the refresh job completes.
     */
    public final static Runnable NO_RUN_AFTER = null;

    /**
     * Pass to runAfter argument of refresh to indicate that the caller
     * should be blocked until the job completes.
     */
    public final static Runnable RUN_ON_CURRENT_THREAD = new Runnable()
    {
        public void run()
        {
            // do nothing
        }
    };

    /**
     * An init-time setting that is used to stop the model processor from
     * automatically refreshing when the file it is tracking changes. The can
     * only be set once at init is permanent for the static life timpe of
     * JSPModelProcessor.
     *
     * Note that it does not turn off listening for file delete events because
     * the singleton management still needs to know if it can dispose of an
     * instance.
     */
    private final static boolean                         DISABLE_WKSPACE_CHANGE_REFRESH = System
                                                                                                .getProperty("org.eclipse.jst.jsf.jspmodelprocessor.disable.wkspace.change.refresh") != null; //$NON-NLS-1$
    private final static Map<IFile, JSPModelProcessor>  RESOURCE_MAP =
        new HashMap<IFile, JSPModelProcessor>();
    private final static java.util.concurrent.locks.Lock CRITICAL_SECTION =
        new  ReentrantLock();
    private static LifecycleListener  LIFECYCLE_LISTENER;

    /**
     * @param file The file to get the model processor for
     * @return the processor for a particular model, creating it if it does not
     *         already exist
     * @throws CoreException if an attempt to get the model associated with file
     *         fails due to reasons other than I/O problems
     */
    public static JSPModelProcessor get(final IFile file) throws CoreException
    {
        CRITICAL_SECTION.lock();
        try
        {
            if (!file.isAccessible())
            {
                throw new CoreException(new Status(IStatus.ERROR, JSFCorePlugin.PLUGIN_ID, "File must be accessible")); //$NON-NLS-1$
            }

            JSPModelProcessor processor = RESOURCE_MAP.get(file);

            if (processor == null)
            {
                if (LIFECYCLE_LISTENER == null)
                {
                    LIFECYCLE_LISTENER = new LifecycleListener(file, ResourcesPlugin.getWorkspace());
                }
                else
                {
                    LIFECYCLE_LISTENER.addResource(file);
                }

                processor = new JSPModelProcessor(file,LIFECYCLE_LISTENER);
                RESOURCE_MAP.put(file, processor);
            }

            return processor;
        }
        finally
        {
            CRITICAL_SECTION.unlock();
        }
    }

    /**
     * Disposes of the JSPModelProcessor associated with model
     * @param file the model processor to be disposed
     */
    private static void dispose(final IFile file)
    {
        CRITICAL_SECTION.lock();
        try
        {
            final JSPModelProcessor processor = RESOURCE_MAP.get(file);

            if (processor != null)
            {
                RESOURCE_MAP.remove(file);

                if (!processor.isDisposed())
                {
                    processor.dispose();
                    LIFECYCLE_LISTENER.removeResource(file);
                }

            }

            if (RESOURCE_MAP.isEmpty())
            {
                // if we no longer have any resources being tracked,
                // then dispose the lifecycle listener
                LIFECYCLE_LISTENER.dispose();
                LIFECYCLE_LISTENER = null;
            }
        }
        finally
        {
            CRITICAL_SECTION.unlock();
        }
    }

    private final IFile             _file;
    private LifecycleListener       _lifecycleListener;
    private IResourceLifecycleListener  _resListener;
    private volatile boolean                 _isDisposed;
    private Map<Object, ISymbol>    _requestMap;
    private Map<Object, ISymbol>    _sessionMap;
    private Map<Object, ISymbol>    _applicationMap;
    private Map<Object, ISymbol>    _noneMap;
    private Map<Object, ISymbol>    _viewMap;
    private Map<Object, ISymbol>    _flashMap;

    // used to avoid infinite recursion in refresh.  Must never be null
    private final CountingMutex     _lastModificationStampMonitor = new CountingMutex();

    /**
     * Construct a new JSPModelProcessor for model
     *
     * @param model
     */
    private JSPModelProcessor(final IFile  file, final LifecycleListener lifecycleListener)
    {
        _file = file;
        _lifecycleListener = lifecycleListener;
        _resListener = new IResourceLifecycleListener()
        {
            public EventResult acceptEvent(final ResourceLifecycleEvent event)
            {
                final EventResult result = EventResult.getDefaultEventResult();

                // not interested
                if (!_file.equals(event.getAffectedResource()))
                {
                    return result;
                }

                if (event.getEventType() == EventType.RESOURCE_INACCESSIBLE)
                {
                    dispose(_file);
                }
                else if (event.getEventType() == EventType.RESOURCE_CHANGED)
                {
                    // if the file has changed contents on disk, then
                    // invoke an unforced refresh of the JSP file
                    if (event.getReasonType() == ReasonType.RESOURCE_CHANGED_CONTENTS
                            && !DISABLE_WKSPACE_CHANGE_REFRESH)
                    {
                        refresh(! FORCE_REFRESH, NO_RUN_AFTER);
                    }
                }

                return result;
            }
        };

        lifecycleListener.addListener(_resListener);
    }

    private IDOMModel getModelForFile(final IFile file)
            throws CoreException, IOException
    {
        final IModelManager modelManager =
            StructuredModelManager.getModelManager();

        final IStructuredModel model = modelManager.getModelForRead(file);

        if (model instanceof IDOMModel)
        {
            return (IDOMModel) model;
        }
        else if (model != null)
        {
            // only release from read if we don't find a DOMModelForJSP
            // if the model is correct, it will be released in dispose
            model.releaseFromRead();
        }
       
        JSFCorePlugin.log("Couldn't get valid model for file: "+file.toString(), new Exception()); //$NON-NLS-1$
        return null;
    }

    private void dispose()
    {
        if (!_isDisposed)
        {
            // ensure the resource listener is disposed
            _lifecycleListener.removeListener(_resListener);
            _resListener = null;
            _lifecycleListener = null;

            if (_requestMap != null)
            {
                _requestMap.clear();
                _requestMap = null;
            }

            if (_sessionMap != null)
            {
                _sessionMap.clear();
                _sessionMap = null;
            }

            if (_applicationMap != null)
            {
                _applicationMap.clear();
                _applicationMap = null;
            }

            if (_noneMap != null)
            {
                _noneMap.clear();
                _noneMap = null;
            }

            // mark as disposed
            _isDisposed = true;
        }
    }

    /**
     * @return true if this model processor has been disposed.  Disposed
     * processors should not be used.
     */
    public boolean isDisposed()
    {
        return _isDisposed;
    }

    /**
     * If isModelDirty() returns true, then it means that a call
     * to refresh(false) will trigger a reprocess of the underlying document.
     *
     * @return true if the underlying JSP model is considered to be dirty
     */
    public boolean isModelDirty()
    {
        final long currentModificationStamp = _file.getModificationStamp();
        return _lastModificationStampMonitor.hasChanged(currentModificationStamp);
    }



    /**
     * Refreshes the processor's cache of information from its associated
     * JSP file.
     *
     * @param forceRefresh
     * @param runAfter
     */
    public void refresh(final boolean forceRefresh, final Runnable runAfter)
    {
        if (isDisposed())
        {
            throw new IllegalStateException(
                    "Processor is disposed for file: " + _file.toString()); //$NON-NLS-1$
        }

        if (runAfter == RUN_ON_CURRENT_THREAD)
        {
            try
            {
                runOnCurrentThread(forceRefresh);
            }
            catch (final CoreException e)
            {
                JSFCorePlugin.log(e, "Running JSP model processor"); //$NON-NLS-1$
            }
            catch (final OperationCanceledException e)
            {
                // ignore
            }
        }
        else
        {
            runOnWorkspaceJob(forceRefresh, runAfter);
        }

    }
    private void runOnWorkspaceJob(final boolean forceRefresh, final Runnable runAfter)
    {
      WorkspaceJob refreshJob = new WorkspaceJob(NLS.bind(Messages
                .getString("JSPModelProcessor.0"), _file)) { //$NON-NLS-1$
            @Override
            public IStatus runInWorkspace(IProgressMonitor monitor)
                    throws CoreException
            {
                RefreshRunnable runnable = new RefreshRunnable(forceRefresh);
                runnable.run(monitor);
                return Status.OK_STATUS;
            }
        };
        refreshJob.setSystem(true);
        refreshJob.setRule(ResourcesPlugin.getWorkspace().getRoot());
        if (runAfter != null)
        {
            refreshJob.addJobChangeListener(new JobChangeAdapter()
            {
                @Override
                public void done(final IJobChangeEvent event)
                {
                    runAfter.run();
                }
            });
        }
        refreshJob.schedule();
    }

    private void runOnCurrentThread(final boolean forceRefresh) throws CoreException, OperationCanceledException
    {
        ResourcesPlugin.getWorkspace().run(new RefreshRunnable(forceRefresh), _file, 0, null);
    }
   
    private final class RefreshRunnable implements IWorkspaceRunnable
    {
        private final boolean _forceRefresh;

        public RefreshRunnable(final boolean forceRefresh)
        {
            _forceRefresh = forceRefresh;
        }

        public void run(final IProgressMonitor monitor)
                throws CoreException
        {
            synchronized (_lastModificationStampMonitor)
            {
                if (!_lastModificationStampMonitor.compareAndSetSignalled(false, true))
                {
                    // if this calls succeeds, then this thread has obtained the
                    // lock already and has called through here before.
                    // return immediately to ensure that we don't recurse
                    // infinitely
                    return;
                }
                IDOMModel model = null;
                try
                {
                    // only refresh if forced or if the underlying file has
                    // changed
                    // since the last run
                    if (_forceRefresh || isModelDirty())
                    {
                        model = getModelForFile(_file);
                        if (model != null)
                        {
                            refreshInternal(model);
                        }
                        _lastModificationStampMonitor.setModificationStamp(_file.getModificationStamp());
                    }
                }
                catch (final IOException e)
                {
                    IStatus status = new Status(IStatus.ERROR, JSFCorePlugin.PLUGIN_ID,"Error refreshing internal model", e); //$NON-NLS-1$
                    final CoreException e2 = new CoreException(status);
                    throw e2;
                }
                // make sure that we unsignal the monitor before releasing the
                // mutex
                finally
                {
                    _lastModificationStampMonitor.setSignalled(false);
                    if (model != null)
                    {
                        model.releaseFromRead();
                    }
                }
            }
        }
    }



    private void refreshInternal(final IDOMModel model)
    {
        final IStructuredDocumentContext context =
            IStructuredDocumentContextFactory.INSTANCE.getContext(model.getStructuredDocument(), -1);
        final ITaglibContextResolver taglibResolver =
            IStructuredDocumentContextResolverFactory.INSTANCE.getTaglibContextResolver(context);
        final IDOMDocument document = model.getDocument();
        getApplicationMap().clear();
        getRequestMap().clear();
        getSessionMap().clear();

        if (taglibResolver == null) {
            // unusual, but protect against possible NPE
            JSFCorePlugin.log(IStatus.ERROR, "Program Error: taglib resolver is null."); //$NON-NLS-1$
            return;
        }

        //long curTime = System.currentTimeMillis();
        recurseChildNodes(model, document.getChildNodes(), taglibResolver);
        //long netTime = System.currentTimeMillis() - curTime;
        //System.out.println("Net time to recurse document: "+netTime);
    }

    private void recurseChildNodes(final IDOMModel model,
                                   final NodeList nodes,
                                    final ITaglibContextResolver taglibResolver)
    {
        for (int i = 0; i < nodes.getLength(); i++)
        {
            final Node child = nodes.item(i);

            // process attributes at this node before recursing
            processAttributes(model, child, taglibResolver);
            recurseChildNodes(model, child.getChildNodes(), taglibResolver);
        }
    }

    private void processAttributes(final IDOMModel model, final Node node,
                                    final ITaglibContextResolver taglibResolver)
    {
        if (taglibResolver.hasTag(node))
        {
            final String uri =
                taglibResolver.getTagURIForNodeName(node);
            final String elementName = node.getLocalName();

            for (int i = 0; i < node.getAttributes().getLength(); i++)
            {
                final Node attribute = node.getAttributes().item(i);

                processSymbolContrib(model, uri, elementName, attribute);
                processSetsLocale(uri, elementName, attribute);
            }
        }
    }

    private void processSymbolContrib(final IDOMModel model, final String uri, final String elementName, final Node attribute)
    {
        final SymbolContribAggregator  aggregator =
            SymbolContribAggregator.
               create(_file, uri, elementName, attribute.getLocalName());

        if (aggregator != null)
        {
            final AbstractContextSymbolFactory factory = aggregator.getFactory();
            final String symbolName = attribute.getNodeValue();

            if (factory != null)
            {
//                long curTime = System.currentTimeMillis();
                final IStructuredDocumentContext context =
                    IStructuredDocumentContextFactory.INSTANCE.
                        getContext(model.getStructuredDocument(),
                           attribute);

                if (factory.supports(context))
                {
                    final List problems = new ArrayList();
                    final ISymbol symbol =
                        factory.create(symbolName,
                                      ISymbolConstants.SYMBOL_SCOPE_REQUEST, //TODO:
                                      context,
                                      problems,
                                      // TODO: add meta-data for signature
                                      new AdditionalContextSymbolInfo(aggregator.getStaticType(), aggregator.getValueExpressionAttr()));

    //                long netTime = System.currentTimeMillis() - curTime;
    //                System.out.println("Time to process loadBundle: "+netTime);

                    if (symbol != null)
                    {
                        updateMap(symbol, aggregator.getScope());
                    }
                }
            }
            else
            {
                final IComponentSymbol componentSymbol =
                    SymbolFactory.eINSTANCE.createIComponentSymbol();
                componentSymbol.setName(symbolName);

                updateMap(componentSymbol, aggregator.getScope());
            }
        }
    }
   
    @SuppressWarnings("deprecation")
    private void processSetsLocale(final String uri, final String elementName, Node attribute)
    {
        LocaleSetAggregator  aggregator = LocaleSetAggregator.create(_file, uri, elementName, attribute.getLocalName());

        if (aggregator != null)
        {
            DesignTimeApplicationManager  dtAppMgr =
                DesignTimeApplicationManager.getInstance(_file.getProject());

            if (dtAppMgr != null)
            {
                DTFacesContext facesContext = dtAppMgr.getFacesContext(_file);
               
                if (facesContext != null)
                {
                    facesContext.setLocaleString(attribute.getNodeValue());
                }
            }
        }
    }

   /**
     * @param scopeName - one of "request", "session" or "application" or "view" if JSF2.x
     * @return an unmodifable map containing all known symbols for
     * that scope.  If scopeName is not found, returns the empty map.
     */
    public Map<Object, ISymbol> getMapForScope(final String scopeName)
    {
        final Map<Object, ISymbol> map = getMapForScopeInternal(scopeName);

        if (map != null)
        {
            return Collections.unmodifiableMap(map);
        }

        return Collections.EMPTY_MAP;
    }

    private void updateMap(final ISymbol symbol, final String  scopeName)
    {
        final Map<Object, ISymbol> map = getMapForScopeInternal(scopeName);

        if (map != null)
        {
            map.put(symbol.getName(), symbol);
        }
        else
        {
            Platform.getLog(JSFCorePlugin.getDefault().getBundle()).log(new Status(IStatus.ERROR, JSFCorePlugin.PLUGIN_ID, 0, "Scope not found: "+scopeName, new Throwable())); //$NON-NLS-1$
        }
    }

    private Map<Object, ISymbol> getMapForScopeInternal(final String scopeName)
    {
        if (ISymbolConstants.SYMBOL_SCOPE_REQUEST_STRING.equals(scopeName))
        {
            return getRequestMap();
        }
        else if (ISymbolConstants.SYMBOL_SCOPE_SESSION_STRING.equals(scopeName))
        {
            return getSessionMap();
        }
        else if (ISymbolConstants.SYMBOL_SCOPE_APPLICATION_STRING.equals(scopeName))
        {
            return getApplicationMap();
        }
        else if (ISymbolConstants.SYMBOL_SCOPE_NONE_STRING.equals(scopeName))
        {
            return getNoneMap();
        }
        else if (ISymbolConstants.SYMBOL_SCOPE_VIEW_STRING.equals(scopeName))
        {
            return getViewMap();
        }
        else if (ISymbolConstants.SYMBOL_SCOPE_FLASH_STRING.equals(scopeName))
        {
            return getFlashMap();
        }

        Platform.getLog(JSFCorePlugin.getDefault().getBundle()).log(new Status(IStatus.ERROR, JSFCorePlugin.PLUGIN_ID, 0, "Scope not found: "+scopeName, new Throwable())); //$NON-NLS-1$
        return null;

    }

    private Map getRequestMap()
    {
        if (_requestMap == null)
        {
            _requestMap = new HashMap<Object, ISymbol>();
        }

        return _requestMap;
    }

    private Map<Object, ISymbol> getSessionMap()
    {
        if (_sessionMap == null)
        {
            _sessionMap = new HashMap<Object, ISymbol>();
        }

        return _sessionMap;
    }

    private Map<Object, ISymbol> getApplicationMap()
    {
        if (_applicationMap == null)
        {
            _applicationMap = new HashMap<Object, ISymbol>();
        }

        return _applicationMap;
    }

    private Map<Object, ISymbol> getNoneMap()
    {
        if (_noneMap == null)
        {
            _noneMap = new HashMap<Object, ISymbol>();
        }

        return _noneMap;
    }
   
    private Map<Object, ISymbol> getViewMap()
    {
        if (_viewMap == null)
        {
          _viewMap = new HashMap<Object, ISymbol>();
        }

        return _viewMap;
    }
   
    private Map<Object, ISymbol> getFlashMap()
    {
        if (_flashMap == null)
        {
          _flashMap = new HashMap<Object, ISymbol>();
        }

        return _flashMap;
    }

    /**
     * Aggregates the sets-locale meta-data
     *
     * @author cbateman
     */
    private static class LocaleSetAggregator
    {
        private final static String SETS_LOCALE = "sets-locale"; //$NON-NLS-1$

        private static LocaleSetAggregator create(final IFile file,
                                              final String uri,
                                              final String elementName, final String attributeName)
        {
        final IMetaDataDomainContext context = MetaDataQueryContextFactory.getInstance().createTaglibDomainModelContext(file);
        final ITaglibDomainMetaDataQuery query = MetaDataQueryFactory.getInstance().createQuery(context);
        final Trait trait = query.getQueryHelper().getTrait(uri, elementName+"/"+attributeName, SETS_LOCALE); //$NON-NLS-1$
//            final ITaglibDomainMetaDataModelContext mdContext = TaglibDomainMetaDataQueryHelper.createMetaDataModelContext(project, uri);
//            final Trait trait = TaglibDomainMetaDataQueryHelper.getTrait(mdContext, elementName+"/"+attributeName, SETS_LOCALE); //$NON-NLS-1$

            if (TraitValueHelper.getValueAsBoolean(trait))
            {
                return new LocaleSetAggregator();
            }

            return null;
        }
    }

    /**
     * Aggregates all the symbol contributor meta-data into a single object
     *
     * @author cbateman
     *
     */
    private static class SymbolContribAggregator
    {
        private final static String CONTRIBUTES_VALUE_BINDING =
            "contributes-value-binding"; //$NON-NLS-1$
        private final static String VALUE_BINDING_SCOPE = "value-binding-scope"; //$NON-NLS-1$
        private final static String VALUE_BINDING_SYMBOL_FACTORY =
            "value-binding-symbol-factory"; //$NON-NLS-1$
        private final static String STATIC_TYPE_KEY = "optional-value-binding-static-type"; //$NON-NLS-1$
        private final static String VALUEEXPRESSION_ATTR_NAME_KEY = "optional-value-binding-valueexpr-attr"; //$NON-NLS-1$

        /**
         * @param attributeName
         * @return a new instance only if attributeName is a symbol contributor
         */
        private static SymbolContribAggregator create(final IFile file,
                                              final String uri,
                                              final String elementName,
                                              final String attributeName)
        {
            final String entityKey = elementName+"/"+attributeName; //$NON-NLS-1$
        final IMetaDataDomainContext context = MetaDataQueryContextFactory.getInstance().createTaglibDomainModelContext(file);
        final ITaglibDomainMetaDataQuery query = MetaDataQueryFactory.getInstance().createQuery(context);
        final Entity entity = query.getQueryHelper().getEntity(uri, entityKey);
        Trait trait = query.getQueryHelper().getTrait(entity, CONTRIBUTES_VALUE_BINDING);
//            final ITaglibDomainMetaDataModelContext mdContext = TaglibDomainMetaDataQueryHelper.createMetaDataModelContext(project, uri);
//            Trait trait = TaglibDomainMetaDataQueryHelper.getTrait(mdContext, entityKey, CONTRIBUTES_VALUE_BINDING);

            final boolean contribsValueBindings = TraitValueHelper.getValueAsBoolean(trait);

            if (contribsValueBindings)
            {
                String scope = null;
                String symbolFactory = null;

                trait = query.getQueryHelper().getTrait(entity, VALUE_BINDING_SCOPE);
                scope = TraitValueHelper.getValueAsString(trait);

                if (scope != null && !scope.equals("")) //$NON-NLS-1$
                {
                    trait = query.getQueryHelper().getTrait(entity, VALUE_BINDING_SYMBOL_FACTORY);
                    symbolFactory = TraitValueHelper.getValueAsString(trait);
                }

                trait = query.getQueryHelper().getTrait(entity, STATIC_TYPE_KEY);

                String staticType = null;

                if (trait != null)
                {
                    staticType = TraitValueHelper.getValueAsString(trait);
                }

                trait = query.getQueryHelper().getTrait(entity, VALUEEXPRESSION_ATTR_NAME_KEY);

                String valueExprAttr = null;
                if (trait != null)
                {
                    valueExprAttr = TraitValueHelper.getValueAsString(trait);
                }

                return new SymbolContribAggregator(scope, symbolFactory, staticType, valueExprAttr);
            }

            return null;
        }

        private final Map<String, String>   _metadata = new HashMap<String, String>(4);

        SymbolContribAggregator(final String scope, final String factory, final String staticType, final String valueExprAttr)
        {
            _metadata.put("scope", scope); //$NON-NLS-1$
            _metadata.put("factory", factory); //$NON-NLS-1$
            _metadata.put("staticType", staticType); //$NON-NLS-1$
            _metadata.put("valueExprAttr", valueExprAttr); //$NON-NLS-1$
        }

        /**
         * @return the scope
         */
        public String getScope()
        {
            return _metadata.get("scope"); //$NON-NLS-1$
        }

        /**
         * @return the factory
         */
        public AbstractContextSymbolFactory getFactory()
        {
            return JSFCommonPlugin.getSymbolFactories().get(_metadata.get("factory")); //$NON-NLS-1$
        }

        public String getStaticType()
        {
            return _metadata.get("staticType"); //$NON-NLS-1$
        }

        public String getValueExpressionAttr()
        {
            return _metadata.get("valueExprAttr"); //$NON-NLS-1$
        }
    }

    private final static class CountingMutex extends Object
    {
        private long                    _lastModificationStamp = -1;
        private boolean _signalled = false;
        private final ILock _lock = Job.getJobManager().newLock();

        /**
         * Similar to AtomicBoolean.compareAndSet.  If the signalled flag
         * is the same as expect then update is written to the flag.  Otherwise,
         * nothing happens.
         * @param expect the value of _signalled where update occurs
         * @param update the value written to _signalled if _signalled == expect
         *
         * @return true if the signalled flag was set to update
         */
        public boolean compareAndSetSignalled(final boolean expect, final boolean update) {
            final boolean[] value = new boolean[1];
            safeRun(new Runnable() {
            public void run()
            {
                if (_signalled == expect)
                {
                    _signalled = update;
                    value[0] = true;
                }
                else
                {
                    value[0] = false;
                }
            }});     
            return value[0];
        }

        public boolean hasChanged(final long currentModificationStamp)
        {
            final boolean[] value = new boolean[1];
            safeRun(new Runnable() {
            public void run()
            {
                value[0] = (_lastModificationStamp != currentModificationStamp);
            }});               
            return value[0];
        }

        /**
         * @param signalled
         */
        public void setSignalled(final boolean signalled) {
            safeRun(new Runnable() {
                public void run()
                {
                    _signalled = signalled;
                }});
        }

        public void setModificationStamp(final long newValue)
        {
            safeRun(new Runnable() {
                public void run()
                {
                    _lastModificationStamp = newValue;
                }});
        }
       
        private void safeRun(final Runnable runnable)
        {
            _lock.acquire();
            try
            {
                runnable.run();
            }
            finally
            {
                _lock.release();
            }
        }
    }
}
TOP

Related Classes of org.eclipse.jst.jsf.designtime.internal.jsp.JSPModelProcessor$CountingMutex

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.