You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by jw...@apache.org on 2013/07/25 18:58:40 UTC
svn commit: r1507065 - in
/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad:
change/InsertedComponentFragmentLocator.java
change/InsertingComponentFragmentLocator.java util/ClassLoaderUtils.java
util/ComponentUtils.java
Author: jwaldman
Date: Thu Jul 25 16:58:39 2013
New Revision: 1507065
URL: http://svn.apache.org/r1507065
Log:
TRINIDAD-2397 Provide API to discover location of document that contains tag definition for a given component
Thanks to Prakash Udupa for the patch
Added:
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/InsertedComponentFragmentLocator.java
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/InsertingComponentFragmentLocator.java
Modified:
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ClassLoaderUtils.java
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ComponentUtils.java
Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/InsertedComponentFragmentLocator.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/InsertedComponentFragmentLocator.java?rev=1507065&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/InsertedComponentFragmentLocator.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/InsertedComponentFragmentLocator.java Thu Jul 25 16:58:39 2013
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidad.change;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+
+/**
+ * Strategy implemented for <em>tags</em> that insert document fragments, returning the URL of the
+ * fragment for any top-level UIComponents inserted by the tag. When determining the URL of the
+ * document that defines the tag corresponding to a target component, clients will call
+ * <code>getFramentUrlForInsertedComponent</code> for each registered
+ * <code>InsertedComponentFragmentLocator</code> on each UIComponent starting from the target
+ * component and upto the UIViewRoot and each registered InsertingComponentFragmentLocator on each
+ * component from the parent of the target component to the UIViewRoot. If a non-null URL string
+ * is returned, the walk of the ancestor chain halts and the returned value is considered the
+ * URL string for the document for the target component. If the registered listeners return
+ * <code>null</code> for every component in the ancestor chain, the containing URL is assumed to be
+ * the URL of the enclosing page.
+ *
+ * Implementations of InsertedComponentFragmentLocator are registered using the normal
+ * Service Provider Interface pattern. A text file named
+ * "org.apache.myfaces.trinidad.change.InsertedComponentFragmentLocator" is placed in the
+ * META-INF/services directory. This file contains the fully qualified class names of all the
+ * InsertedComponentFragmentLocator strategy to register.
+ *
+ * @see InsertingComponentFragmentLocator
+ */
+public abstract class InsertedComponentFragmentLocator
+{
+ /**
+ * Returns the URL string of the fragment that contains tag corresponding to
+ * <code>componentToTest</code>, or <code>null</code> if this InsertedComponentFragmentLocator
+ * could not determine the URL.
+ * @param context The FacesContext instance for current request
+ * @param componentToTest The component to determine the fragment URL for.
+ * <code>componentToTest</code> will be the <code>targetComponent</code>,
+ * or one of its ancestors. EL context will NOT be setup for
+ * <code>componentToTest</code> when this method is called.
+ * @param targetComponent The target component for which we are ultimately trying to determine the
+ * fragment URL. It is assumed that this URL will be same as the URL
+ * obtained for <code>componenToTest</code>
+ */
+ public abstract String getFragmentUrlForInsertedComponent(
+ FacesContext context,
+ UIComponent componentToTest,
+ UIComponent targetComponent);
+}
Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/InsertingComponentFragmentLocator.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/InsertingComponentFragmentLocator.java?rev=1507065&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/InsertingComponentFragmentLocator.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/InsertingComponentFragmentLocator.java Thu Jul 25 16:58:39 2013
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidad.change;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+
+/**
+ * Strategy implemented for <em>components</em> that insert document fragments to return the URL of
+ * the fragment currently inserted by this component. When determining the URL of the
+ * document that defines the tag corresponding to a target component, clients will call
+ * <code>getFramentUrlForInsertedComponent</code> for each registered
+ * <code>InsertedComponentFragmentLocator</code> on each UIComponent starting from the target
+ * component and upto the UIViewRoot and each registered InsertingComponentFragmentLocator on each
+ * component from the parent of the target component to the UIViewRoot. If a non-null URL string
+ * is returned, the walk of the ancestor chain halts and the returned value is considered the
+ * URL string for the document for the target component. If the registered listeners return
+ * <code>null</code> for every component in the ancestor chain, the containing URL is assumed to be
+ * the URL of the enclosing page.
+ *
+ * Implementations of InsertingComponentFragmentLocator are registered using the normal
+ * Service Provider Interface pattern. A text file named
+ * "org.apache.myfaces.trinidad.change.InsertingComponentFragmentLocator" is placed in the
+ * META-INF/services directory. This file contains the fully qualified class names of all the
+ * InsertingComponentFragmentLocator strategy to register.
+ *
+ * @see InsertedComponentFragmentLocator
+ */
+public abstract class InsertingComponentFragmentLocator
+{
+ /**
+ * Returns the URL string of the fragment inserted by <code>componentToTest</code>, or
+ * <code>null</code> if this InsertingComponentFragmentLocator could not determine the URL.
+ * @param context The FacesContext instance for current request
+ * @param componentToTest The component that possibly inserted the targetComponent. This component
+ * will be used to determine the fragment URL for targetComponent.
+ * <code>componentToTest</code> will be an ancestor of the
+ * <code>targetComponent</code>. EL context will NOT be setup for
+ * <code>componentToTest</code> when this method is called.
+ * @param targetComponent The component to determine the fragment URL for
+ */
+ public abstract String getInsertedFragmentUrl(
+ FacesContext context,
+ UIComponent componentToTest,
+ UIComponent targetComponent);
+}
Modified: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ClassLoaderUtils.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ClassLoaderUtils.java?rev=1507065&r1=1507064&r2=1507065&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ClassLoaderUtils.java (original)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ClassLoaderUtils.java Thu Jul 25 16:58:39 2013
@@ -19,9 +19,8 @@
package org.apache.myfaces.trinidad.util;
import java.io.BufferedReader;
-import java.io.InputStream;
import java.io.IOException;
-
+import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
@@ -31,9 +30,10 @@ import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
-
import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import org.apache.myfaces.trinidad.context.RequestContext;
import org.apache.myfaces.trinidad.logging.TrinidadLogger;
/**
@@ -257,7 +257,42 @@ public final class ClassLoaderUtils
{
return getServices(service.getName());
}
+
+ /**
+ * Gets all the registered services of the supplied type. Once instantiated, the services are
+ * cached in the application scoped storage, and any further requests to this function will
+ * get the cached services. It is assumed that the name of the service file and the type of
+ * the service class is the same.
+ * @param service The class type of the service
+ * @return The list of registered service instances
+ */
+ static <T> List<T> __getCachableServices(Class<T> service)
+ {
+ List<T> services = Collections.emptyList();
+ String serviceName = service.getName();
+ ConcurrentMap<String, Object> concurrentAppMap =
+ RequestContext.getCurrentInstance().getApplicationScopedConcurrentMap();
+ Object serviceObject = concurrentAppMap.get(serviceName);
+ if (serviceObject == null)
+ {
+ services = ClassLoaderUtils.getServices(service);
+ Object oldValue = concurrentAppMap.putIfAbsent(serviceName, services);
+
+ // if a different thread raced us and added one, use that
+ if (oldValue != null)
+ {
+ services = (List<T>) oldValue;
+ }
+ }
+ else
+ {
+ services = (List<T>) serviceObject;
+ }
+
+ return services;
+ }
+
/**
* Instantiate all available services from a file in /META-INF/services.
* <P>
Modified: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ComponentUtils.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ComponentUtils.java?rev=1507065&r1=1507064&r2=1507065&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ComponentUtils.java (original)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ComponentUtils.java Thu Jul 25 16:58:39 2013
@@ -19,21 +19,21 @@
package org.apache.myfaces.trinidad.util;
import java.util.Date;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponent;
-
import javax.faces.component.UIViewRoot;
-
import javax.faces.component.visit.VisitContext;
-
-import org.apache.myfaces.trinidad.component.UIXComponent;
import javax.faces.context.FacesContext;
+import org.apache.myfaces.trinidad.change.InsertedComponentFragmentLocator;
+import org.apache.myfaces.trinidad.change.InsertingComponentFragmentLocator;
import org.apache.myfaces.trinidad.component.FlattenedComponent;
+import org.apache.myfaces.trinidad.component.UIXComponent;
import org.apache.myfaces.trinidad.logging.TrinidadLogger;
/**
@@ -440,6 +440,89 @@ public final class ComponentUtils
}
/**
+ * Gets the location (context relative path) of the document that contains the tag definition
+ * corresponding to the supplied component. This implementation uses the
+ * InsertedComponentFragmentLocator and InsertingComponentFragmentLocator strategies to determine
+ * the document path for the supplied component.
+ * All registered InsertedComponentFragmentLocator services are first asked for location of the
+ * document for the supplied component first. If the locator could not be obtained, then this
+ * implementation will walk up the component tree and for every ancestor until the view root,
+ * call all the registered InsertedComponentFragmentLocator and InsertingComponentFragmentLocator
+ * services to obtain the location of the document. If in this process any non-null value is
+ * obtained for the document location, the ancestor processing is halted and the value is
+ * returned.
+ *
+ * @param context The FacesContext instance for the current request
+ * @param component The component for which the document path is to be determined
+ * @return Location of the document fragment that contains the tag corresponding to the supplied
+ * component. Returns null if the path cannot be determined.
+ */
+ public static String getDocumentLocationForComponent(
+ FacesContext context,
+ UIComponent component)
+ {
+ UIViewRoot viewRoot = context.getViewRoot();
+
+ // if we are dealing with view root, look no further
+ if (component == viewRoot)
+ {
+ return viewRoot.getViewId();
+ }
+
+ String location = null;
+
+ List<InsertedComponentFragmentLocator> insertedComponentFragmentLocators =
+ ClassLoaderUtils.__getCachableServices(InsertedComponentFragmentLocator.class);
+
+ // 1. try to get the path for the supplied component
+ location = _getInsertedComponentLocation(context,
+ insertedComponentFragmentLocators,
+ component,
+ component);
+
+ // 2. try to get the path for the supplied component using its ancestors
+ if (location == null)
+ {
+ List<InsertingComponentFragmentLocator> insertingComponentFragmentLocators =
+ ClassLoaderUtils.__getCachableServices(InsertingComponentFragmentLocator.class);
+
+ UIComponent currAncestor = component.getParent();
+
+ while (currAncestor != null)
+ {
+ if (currAncestor == viewRoot)
+ {
+ return viewRoot.getViewId();
+ }
+
+ // 2a. try to get the location where the tag for ancestor is defined
+ location = _getInsertedComponentLocation(context,
+ insertedComponentFragmentLocators,
+ currAncestor,
+ component);
+
+ if (location == null)
+ {
+ // 2b. try to get the location of the fragment that the ancestor could have inserted
+ location = _getInsertingComponentLocation(context,
+ insertingComponentFragmentLocators,
+ currAncestor,
+ component);
+
+ if (location != null)
+ {
+ break;
+ }
+ }
+
+ currAncestor = currAncestor.getParent();
+ }
+ }
+
+ return location;
+ }
+
+ /**
* Gets the scoped identifier for the target component. The scoping will be
* within a subtree rooted by the supplied base component. If the supplied
* base component were to be the view root, the returned id will be the
@@ -566,6 +649,58 @@ public final class ComponentUtils
return null;
}
+ /**
+ * Iterates through all the registered InsertedComponentFragmentLocator services and gets
+ * the location of the fragment document where the tag corresponding to the supplied
+ * componentToTest is defined. Returns null if the location cannot be determined.
+ */
+ private static String _getInsertedComponentLocation(
+ FacesContext context,
+ List<InsertedComponentFragmentLocator> insertedComponentFragmentLocators,
+ UIComponent componentToTest,
+ UIComponent targetComponent)
+ {
+ for (InsertedComponentFragmentLocator
+ insertedComponentFragmentLocator : insertedComponentFragmentLocators)
+ {
+ String location =
+ insertedComponentFragmentLocator.getFragmentUrlForInsertedComponent(context,
+ componentToTest,
+ targetComponent);
+ if (location != null)
+ {
+ return location;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Iterates through all the registered InsertingComponentFragmentLocator services and gets
+ * the location of the fragment document that the supplied componentToTest could have possibly
+ * inserted. Returns null if the location cannot be determined.
+ */
+ private static String _getInsertingComponentLocation(
+ FacesContext context,
+ List<InsertingComponentFragmentLocator> insertingComponentFragmentLocators,
+ UIComponent componentToTest,
+ UIComponent targetComponent)
+ {
+ for (InsertingComponentFragmentLocator
+ insertingComponentFragmentLocator : insertingComponentFragmentLocators)
+ {
+ String location =
+ insertingComponentFragmentLocator.getInsertedFragmentUrl(context,
+ componentToTest,
+ targetComponent);
+ if (location != null)
+ {
+ return location;
+ }
+ }
+ return null;
+ }
+
private static boolean _isFlattening(FacesContext context, UIComponent component)
{
return ((component instanceof FlattenedComponent) &&