Package org.eclipse.jst.jsf.designtime.internal.view.model.jsp.registry

Source Code of org.eclipse.jst.jsf.designtime.internal.view.model.jsp.registry.TLDTagRegistry$MyPropertyListener

/*******************************************************************************
* 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.designtime.internal.view.model.jsp.registry;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jst.jsf.common.internal.managedobject.IManagedObject;
import org.eclipse.jst.jsf.common.internal.policy.IdentifierOrderedIteratorPolicy;
import org.eclipse.jst.jsf.common.runtime.internal.view.model.common.Namespace;
import org.eclipse.jst.jsf.core.internal.JSFCorePlugin;
import org.eclipse.jst.jsf.core.internal.JSFCoreTraceOptions;
import org.eclipse.jst.jsf.designtime.internal.Messages;
import org.eclipse.jst.jsf.designtime.internal.view.model.AbstractTagRegistry;
import org.eclipse.jst.jsf.designtime.internal.view.model.jsp.CompositeTagResolvingStrategy;
import org.eclipse.jst.jsf.designtime.internal.view.model.jsp.DefaultJSPTagResolver;
import org.eclipse.jst.jsf.designtime.internal.view.model.jsp.TLDNamespace;
import org.eclipse.jst.jsf.designtime.internal.view.model.jsp.TagIntrospectingStrategy;
import org.eclipse.jst.jsf.designtime.internal.view.model.jsp.UnresolvedJSPTagResolvingStrategy;
import org.eclipse.jst.jsf.designtime.internal.view.model.jsp.persistence.PersistedDataTagStrategy;
import org.eclipse.jst.jsp.core.internal.contentmodel.tld.CMDocumentFactoryTLD;
import org.eclipse.jst.jsp.core.internal.contentmodel.tld.provisional.TLDDocument;
import org.eclipse.jst.jsp.core.internal.contentmodel.tld.provisional.TLDElementDeclaration;
import org.eclipse.jst.jsp.core.taglib.ITLDRecord;
import org.eclipse.jst.jsp.core.taglib.ITaglibRecord;
import org.eclipse.jst.jsp.core.taglib.TaglibIndex;

/**
* Registry of all tld-defined tags for a particular project classpath
*
* @author cbateman
*
*/
public final class TLDTagRegistry extends AbstractTagRegistry implements
        IManagedObject
{
    // INSTANCE
    private final IProject                                             _project;
    private final Map<String, TLDNamespace>                            _nsResolved;
    private final CompositeTagResolvingStrategy<TLDElementDeclaration> _resolver;
    private boolean                                                    _hasBeenInitialized = false;
    private final ConcurrentLinkedQueue<LibraryOperation>              _changeOperations   = new ConcurrentLinkedQueue<LibraryOperation>();
    private final Job                                                  _changeJob;
    private final PersistedDataTagStrategy                             _persistedTagStrategy;
    private TagIndexListener                                           _tagIndexListener;
    private final TLDRegistryPreferences                               _prefs;
    private final MyPropertyListener                                   _myPropertyListener;

    TLDTagRegistry(final IProject project)
    {
        _project = project;
        _nsResolved = new HashMap<String, TLDNamespace>();

        _prefs = new TLDRegistryPreferences(JSFCorePlugin.getDefault().getPreferenceStore());
        _myPropertyListener = new MyPropertyListener();
        _prefs.addListener(_myPropertyListener);
        _prefs.load();
        final IdentifierOrderedIteratorPolicy<String> policy =
            getTagResolvingPolicy();

        _resolver = new CompositeTagResolvingStrategy<TLDElementDeclaration>(
                policy);

        // add the strategies
        _resolver.addStrategy(new TagIntrospectingStrategy(_project));
        _resolver.addStrategy(new DefaultJSPTagResolver(_project));
        // makes sure that a tag element will always be created for any
        // given tag definition even if other methods fail
        _resolver.addStrategy(new UnresolvedJSPTagResolvingStrategy());
        _persistedTagStrategy = new PersistedDataTagStrategy(_project);
        _persistedTagStrategy.init();
        _resolver.addStrategy(_persistedTagStrategy);

        _changeJob = new ChangeJob(project.getName());
    }

    private IdentifierOrderedIteratorPolicy<String>  getTagResolvingPolicy()
    {
        // strategy ordering
        final List<String>  prefOrdering = _prefs.getEnabledIds();
        final List<String> strategyOrdering = new ArrayList<String>(prefOrdering);
       
        // this strategy must always be here, always last
        strategyOrdering.add(UnresolvedJSPTagResolvingStrategy.ID);

        final IdentifierOrderedIteratorPolicy<String> policy = new IdentifierOrderedIteratorPolicy<String>(
                strategyOrdering);
        // exclude things that are not explicitly listed in the policy.  That
        // way preference-based disablement will cause those strategies to
        // be excluded.
        policy.setExcludeNonExplicitValues(true);
        return  policy;
    }

    protected final void doDispose()
    {
        if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY)
        {
            JSFCoreTraceOptions.log("TLDTagRegistry: Disposing for project " //$NON-NLS-1$
                    + _project.toString());
        }

        // call checkpoint to flush serializable data
        checkpoint();
        //_persistedTagStrategy.dispose();

        _prefs.removeListener(_myPropertyListener);
        _prefs.dispose();

        _nsResolved.clear();
        _changeOperations.clear();

        if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY)
        {
            JSFCoreTraceOptions
                    .log("TLDTagRegistry: Done disposing registry for " //$NON-NLS-1$
                            + _project.toString());
        }
    }

    @Override
    protected void cleanupPersistentState()
    {
       // TODO
    }

    public synchronized void checkpoint()
    {
        try
        {
            _persistedTagStrategy.save(_nsResolved);
        }
        catch (IOException e)
        {
           JSFCorePlugin.log(e, "Checkpointing JSP tags failed"); //$NON-NLS-1$
        }
        catch (ClassNotFoundException e)
        {
            JSFCorePlugin.log(e, "Checkpointing JSP tags failed"); //$NON-NLS-1$
        }
    }

    @Override
    protected Job getRefreshJob(final boolean flushCaches)
    {
        return new Job(Messages.TLDTagRegistry_RefreshJob + _project.getName())
        {
            @Override
            protected IStatus run(final IProgressMonitor monitor)
            {
                if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY)
                {
                    JSFCoreTraceOptions.log("TLDTagRegistry.refresh: start"); //$NON-NLS-1$
                }

                synchronized (TLDTagRegistry.this)
                {
                    if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY)
                    {
                        JSFCoreTraceOptions
                                .log("TLDTagRegistry.refresh: start"); //$NON-NLS-1$
                    }

                    final List<Namespace> namespaces = new ArrayList(
                            _nsResolved.values());

                    if (flushCaches)
                    {
                        _persistedTagStrategy.clear();
                    }
                    // if we aren't flushing caches, then check point the
                    // current namespace data, so it isn't lost when we clear
                    // the namespaces
                    else
                    {
                        checkpoint();
                    }

                    _nsResolved.clear();

                    fireEvent(new TagRegistryChangeEvent(TLDTagRegistry.this,
                            TagRegistryChangeEvent.EventType.REMOVED_NAMESPACE,
                            namespaces));
                    initialize(true);

                    if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY)
                    {
                        JSFCoreTraceOptions
                                .log("TLDTagRegistry.refresh: finished"); //$NON-NLS-1$
                    }
                    return Status.OK_STATUS;
                }
            }
        };
    }

    /**
     */
    private void initialize(boolean fireEvent)
    {
        if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY)
        {
            JSFCoreTraceOptions.log("TLDTagRegistry.initialize: start"); //$NON-NLS-1$
        }

        final ITaglibRecord[] tldrecs = TaglibIndex
                .getAvailableTaglibRecords(_project.getFullPath());
        final List<Namespace> affectedObjects = new ArrayList<Namespace>();
        for (final ITaglibRecord tldrec : tldrecs)
        {
            // defer the event
            final Namespace ns = initialize(tldrec, fireEvent);

            if (ns != null)
            {
                affectedObjects.add(ns);
            }
        }

        _hasBeenInitialized = true;

        // if tag index listener does exist, add it
        if (_tagIndexListener == null)
        {
            if (JSFCoreTraceOptions.TRACE_TLDREGISTRYMANAGER)
            {
                JSFCoreTraceOptions
                        .log("TLDRegistryManager: installing tag index listener due to create instance for " //$NON-NLS-1$
                                + _project.toString());
            }

            _tagIndexListener = new TagIndexListener(this);
            TaglibIndex.addTaglibIndexListener(_tagIndexListener);
        }

        // if (affectedObjects.size() > 0)
        // {
        // fireEvent(new TagRegistryChangeEvent(this,
        // TagRegistryChangeEvent.EventType.ADDED_NAMESPACE,
        // affectedObjects));
        // }

        if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY)
        {
            JSFCoreTraceOptions.log("TLDTagRegistry.initialize: finished"); //$NON-NLS-1$
        }
    }

    TLDNamespace initialize(final ITaglibRecord tagRecord,
            final boolean fireEvent)
    {
        if (tagRecord.getRecordType() == ITLDRecord.URL)
        {
            if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY_CHANGES)
            {
                JSFCoreTraceOptions.log("TLDTagRegistry.initialize_TagRecord: Initializing new tld record: "+tagRecord.toString()); //$NON-NLS-1$
            }
            long startTime = 0;
           
            if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY_PERF)
            {
                startTime = System.nanoTime();
            }
           
            final CMDocumentFactoryTLD factory = new CMDocumentFactoryTLD();
            final TLDDocument doc = (TLDDocument) factory
                    .createCMDocument(tagRecord);
            if (doc != null)
            {
                final TLDNamespace ns = new TLDNamespace(doc, _resolver);
                _nsResolved.put(doc.getUri(), ns);
   
                if (fireEvent)
                {
                    fireEvent(new TagRegistryChangeEvent(this,
                            TagRegistryChangeEvent.EventType.ADDED_NAMESPACE,
                            Collections.singletonList(ns)));
                }

                if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY_PERF)
                {
                    System.out.printf("Time to update namespace %s was %d\n", //$NON-NLS-1$
                            ns.getNSUri(), Long.valueOf(System.nanoTime()
                                    - startTime));
                }
                return ns;
            }
        }
        else
        {
            if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY_CHANGES)
            {
                JSFCoreTraceOptions.log("TLDTagRegistry.initialize_TagRecord: Skipping tag record for "+tagRecord.toString()); //$NON-NLS-1$
            }

        }
        // no new namespace
        return null;
    }

    void remove(final ITaglibRecord tagRecord)
    {
        // this is safer, since we likely fail to create a TLDDocument for
        // a tagRecord that has been removed.
        final String uri = tagRecord.getDescriptor().getURI();
        final TLDNamespace ns = _nsResolved.remove(uri);

        if (ns != null)
        {
            fireEvent(new TagRegistryChangeEvent(this,
                    TagRegistryChangeEvent.EventType.REMOVED_NAMESPACE,
                    Collections.singletonList(ns)));
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.jst.jsf.designtime.internal.view.model.jsp.registry.ITagRegistry#getAllTagLibraries()
     */
    public final synchronized Collection<? extends Namespace> getAllTagLibraries()
    {
        if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY)
        {
            JSFCoreTraceOptions.log("TLDTagRegistry.getAllTagLibraries: start"); //$NON-NLS-1$
        }
        long startTime = 0;
       
        if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY_PERF)
        {
            startTime = System.nanoTime();
        }
       
        if (!_hasBeenInitialized)
        {
            initialize(false);
        }

        final Set<TLDNamespace> allTagLibraries = new HashSet<TLDNamespace>();
        allTagLibraries.addAll(_nsResolved.values());

        if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY_PERF)
        {
            System.out.println("Time to getAllTagLibraries for JSP: "+(System.nanoTime()-startTime)); //$NON-NLS-1$
        }
        if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY)
        {
            JSFCoreTraceOptions
                    .log("TLDTagRegistry.getAllTagLibraries: finished"); //$NON-NLS-1$
        }
        return allTagLibraries;
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.jst.jsf.designtime.internal.view.model.jsp.registry.ITagRegistry#getTagLibrary(java.lang.String)
     */
    public final synchronized Namespace getTagLibrary(final String uri)
    {
        if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY)
        {
            JSFCoreTraceOptions.log("TLDTagRegistry.getTagLibrary: start uri=" //$NON-NLS-1$
                    + uri);
        }

        if (!_hasBeenInitialized)
        {
            initialize(false);
        }

        final Namespace ns = _nsResolved.get(uri);

        if (JSFCoreTraceOptions.TRACE_JSPTAGREGISTRY)
        {
            JSFCoreTraceOptions
                    .log("TLDTagRegistry.getTagLibrary: finished, result=" //$NON-NLS-1$
                            + ns.toString());
        }
        return ns;
    }

    @Override
    public String toString()
    {
        return String
                .format(
                        "TLDRegistry for project %s, isDisposed=%s, hasBeenInitialized=%s, numberOfNamespace=%d", //$NON-NLS-1$
                        _project.toString(), Boolean.valueOf(isDisposed()),
                        Boolean.valueOf(_hasBeenInitialized), Integer
                                .valueOf(_nsResolved.size()));
    }

    void addLibraryOperation(final LibraryOperation operation)
    {
        _changeOperations.add(operation);
        _changeJob.schedule();
    }


    private class ChangeJob extends Job
    {
        private int _rescheduleTime = -1;

        public ChangeJob(final String projectName)
        {
            super(Messages.TLDTagRegistry_UpdateJob + projectName);
        }

        @Override
        protected IStatus run(final IProgressMonitor monitor)
        {
            synchronized (TLDTagRegistry.this)
            {
                _rescheduleTime = -1;

                LibraryOperation operation = null;
                final MultiStatus multiStatus = new MultiStatus(
                        JSFCorePlugin.PLUGIN_ID, 0, "Result of change job", //$NON-NLS-1$
                        new Throwable());
                while ((operation = _changeOperations.poll()) != null)
                {
                    _rescheduleTime = 10000; // ms

                    operation.run();
                    multiStatus.add(operation.getResult());
                }

                if (_rescheduleTime >= 0 && !monitor.isCanceled())
                {
                    // if any operations were found on this run, reschedule
                    // to run again in 10seconds based on the assumption that
                    // events may be coming in bursts
                    schedule(_rescheduleTime);
                }

                return multiStatus;
            }
        }
    }
   
    private class MyPropertyListener extends TLDRegistryPreferences.PropertyListener
    {
        @Override
        public void strategyOrderChanged()
        {
            synchronized(TLDTagRegistry.this)
            {
                _prefs.load();
                final IdentifierOrderedIteratorPolicy<String> policy =
                    getTagResolvingPolicy();
                _resolver.setPolicy(policy);
            }
        }
    }
}
TOP

Related Classes of org.eclipse.jst.jsf.designtime.internal.view.model.jsp.registry.TLDTagRegistry$MyPropertyListener

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.