[Yanel-dev] [HEADS UP] ResourceManager and ResourceConfigurationMap class may die soon; resource-types' URL matching (e.g. on request parameters)

Guillaume Déflache guillaume.deflache at wyona.com
Fri Dec 4 22:19:58 CET 2009


Some progress report as Simon showed some renewed interest in this =

lately! ;)
Cf. =

http://lists.wyona.org/pipermail/yanel-development/2009-December/004192.html

Guillaume D=E9flache a =E9crit :
> Hi!
> =

> As discussed with Simon some time ago (unfortunately no one took notes =

> :(...) we would like to be able to choose the resource-type to use for a =

> request by matching the value or presence of HTTP request parameters =

> (ATM one can only match on the request URI).
> =

> As far as Michi and I can remember, we then considered at least 2 options:
> =

> =

> *Option 1*: allow a syntax similar to "**?my-param-name=3D*" in map.rc-ma=
p =

> files in "matcher" elements for the "pattern" attribute.
> =

> Some issues:
> - most probably we want to ignore the order of the request parameters as =

> they are written in the pattern, as anyway AFAIK the servlet spec does =

> not define it
> - should we also match parameters passed through POST, albeit the syntax =

> of the pattern could make use think it would only work for GET: Mich and =

> I would say we should, and the servlet API makes that choice easier
> - what would "**" mean in the query string part? I'd suggest it should =

> either throw some parsing exception, or match any other parameter that =

> could also be present (would allow use to distinguish between the two =

> cases "only these parameters" and "these parameters and some others we =

> do not care about", although that might be somewhat counter-intuitive)

Any opinion about these issues, esp. Simon? On the 3rd I'd personally go =

for the "match any other parameter" solution.


> *Option 2*: allow full customization of the matching policy by =

> introducing a new Java interface for it.
> (1st please note that #1 can readily be implemented independently of #2 =

> but of course we'd rather put new functionality in the new places if =

> possible.)

I did some (unfinished) work on this, please review the attachment.
There is still some unfinished stuff, mainly around the TODO and XXX =

markers, please ask me as they probably won't make any sense to anyone =

else than me.


> This interface would be almost identical to the =

> org.wyona.yanel.core.ResourceManager class's (minus the deprecated =

> parts) and especially provide getResource(Environment environment, Realm =

> realm, String path, ResourceConfiguration rc): having access to the =

> environment should allow any future kind of matching imaginable (see =

> Apache Cocoon for wild ideas! ;) ).
> I'd suggest to use a better name (*Manager is rather uninspiring): =

> org.wyona.yanel.core.api.ResourceTypeMatcherV1 maybe?

The current interface has the same name but provide =

getResourceConfiguration(Environment environment, Realm realm, String =

path) instead: indeed IMHO what we need to be configurable is only the =

RC object selector, not a Resource selector (all Resource objects may be =

instantiated in the same way for now, better not expose classloading =

guts before we get our runtime-modularity story right).


> Then as 1st step we would have to reimplement =

> org.wyona.yanel.core.ResourceManager using the new interface and still =

> use it as the default for backward-compatibility.
> Then we would have to allow configuration of the concrete matching =

> class. ATM this is done in the Yanel class, but Michi would like it to =


That's more or less what is done in the patch.


> be configurable per realm, and thanks to the way it's currently =

> encapsulated there this is also possible only with some more =

> deprecations (namely Yanel.getResourceManager).

I did not tackle that yet.

We may not need to change Yanel#getResourceManager or even =

ResourceManager to do this, as ResourceManager#getResource has already =

the realm as parameter.
Maybe the ResourceManager should/could become a registry of =

ResourceTypeMatcherV1 objects for all realms, adn then we would only =

need =

ResourceManager#setResourceTypeMatcherForRealm(ResourceTypeMatcherV1 =

matcher, Realm realm)??? But then maybe we would only need =

ResourceTypeMatcherV1#getResourceConfiguration(Environment environment, =

String path) without the realm parameter?

Or maybe we should wait and do that in ResourceTypeMatcherV2?


> I'd also suggest we hide functionality actually in =

> ResourceConfigurationMap in the concrete matcher implementations: the =

> class only has static methods and needlessly expose mechanics. It also =


This still can/should be done once dust has settled on all things above.

> needs changing because Michi would like to be able to parametrize the =

> "map.rc-map" file name.


This will probably be left as an exercise to casual contributors! :P


Cheers,
    Guillaume
-------------- next part --------------
Index: conf/spring-yanel-config.xml
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- conf/spring-yanel-config.xml	(Revision 45854)
+++ conf/spring-yanel-config.xml	(Arbeitskopie)
@@ -23,6 +23,8 @@
 -->
   <bean id=3D"PolicyManagerFactory" class=3D"org.wyona.security.impl.Polic=
yManagerFactoryImpl"/>
   <bean id=3D"IdentityManagerFactory" class=3D"org.wyona.security.impl.Ide=
ntityManagerFactoryImpl"/>
+  <bean id=3D"ResourceTypeMatcherV1" class=3D"org.wyona.yanel.impl.Resourc=
eTypeDefaultMatcher"/>
+  <!--bean id=3D"ResourceTypeMatcherV1" class=3D"org.wyona.yanel.core.Reso=
urceManager"/-->
 =

   <bean id=3D"repo-navigation" class=3D"org.wyona.yanel.impl.navigation.Si=
tetreeResConfigAndDataRepoImpl"/>
 <!--
Index: src/core/java/org/wyona/yanel/core/Yanel.java
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/core/java/org/wyona/yanel/core/Yanel.java	(Revision 45854)
+++ src/core/java/org/wyona/yanel/core/Yanel.java	(Arbeitskopie)
@@ -16,6 +16,7 @@
 =

 package org.wyona.yanel.core;
 =

+import org.wyona.yanel.core.api.ResourceTypeMatcherV1;
 import org.wyona.yanel.core.map.Map;
 import org.wyona.yanel.core.map.Realm;
 import org.wyona.yanel.core.map.RealmManager;
@@ -79,6 +80,13 @@
        rtr =3D new ResourceTypeRegistry();
        resourceManager =3D new ResourceManager();
        resourceManager.setResourceTypeRegistry(rtr);
+       ResourceTypeMatcherV1 rtm =3D getServiceInstance(ResourceTypeMatche=
rV1.class);
+       if (rtm =3D=3D null) {
+           log.info("No custom resource type matcher service found, using =
default one.");
+       } else {
+           resourceManager.setResourceTypeMatcher(rtm);
+           log.info("Found "+rtm.getClass().getCanonicalName()+" resource =
type matcher service, using that!");
+       }
        =

 /* TODO: Why is this commented?
        PolicyManager pm =3D (PolicyManager) yanel.getBeanFactory().getBean=
("policyManager");
@@ -133,7 +141,13 @@
         log.warn("DEPRECATED");
         return applicationContext;
     }
-    =

+
+    @SuppressWarnings("unchecked")
+    private <O extends Object> O getServiceInstance(Class<O> clazz) throws=
 Exception {
+        O service =3D (O) yanel.getBeanFactory().getBean(clazz.getSimpleNa=
me());
+        return service;
+    }
+
     /**
      * Get repository factory
      * @param id Repository factory bean ID
Index: src/core/java/org/wyona/yanel/core/ResourceManager.java
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/core/java/org/wyona/yanel/core/ResourceManager.java	(Revision 45854)
+++ src/core/java/org/wyona/yanel/core/ResourceManager.java	(Arbeitskopie)
@@ -22,6 +22,7 @@
 import javax.servlet.http.HttpServletRequest;
 =

 import org.apache.log4j.Logger;
+import org.wyona.yanel.core.api.ResourceTypeMatcherV1;
 import org.wyona.yanel.core.map.Realm;
 import org.wyona.yanel.core.util.HttpServletRequestHelper;
 import org.wyona.yanel.core.util.PathUtil;
@@ -32,16 +33,22 @@
  *  given some initial resource-type-related configuration
  *  and some context for the request.
  */
-public class ResourceManager {
+public class ResourceManager implements ResourceTypeMatcherV1 {
 =

     private static Logger log =3D Logger.getLogger(ResourceManager.class);
     =

     protected ResourceTypeRegistry rtRegistry;
     =

+    private ResourceTypeMatcherV1 RTmatcher =3D this;
+
     public void setResourceTypeRegistry(ResourceTypeRegistry registry) {
         this.rtRegistry =3D registry;
     }
 =

+    public void setResourceTypeMatcher(ResourceTypeMatcherV1 matcher) { //=
XXX maybe use constructor injection
+        this.RTmatcher =3D matcher;
+    }
+
     /**
      * Creates a new resource object in the given realm with the given pat=
h and the given type.
      * @deprecated Use {@link #getResource(Environment, Realm, String, Res=
ourceConfiguration)} instead,
@@ -110,10 +117,17 @@
      * @param path Path relative to realm (e.g. yanel.getMap().getPath(rea=
lm, request.getServletPath()))
      */
     public Resource getResource(Environment environment, Realm realm, Stri=
ng path) throws Exception {
+        ResourceConfiguration rc =3D RTmatcher.getResourceConfiguration(en=
vironment, realm, path);
+        Resource resource =3D getResource(environment, realm, path, rc);
+        return resource;
+    }
+
+    //XXX won't fallback if class not found
+    public ResourceConfiguration getResourceConfiguration(Environment envi=
ronment, Realm realm, String path) throws Exception {
         // Check first if a one-to-one mapping exists
         if (realm.getRTIRepository().existsNode(PathUtil.getRCPath(path)))=
 {
             ResourceConfiguration rc =3D new ResourceConfiguration(realm.g=
etRTIRepository().getNode(PathUtil.getRCPath(path)));
-            if (rc !=3D null) return getResource(environment, realm, path,=
 rc);
+            return rc; //TODO check null check!
         }
 =

         // Fallback to deprecated RTI (one-to-one mapping)
@@ -121,7 +135,7 @@
             log.warn("DEPRECATED: RTI should be replaced by ResourceConfig=
uration: " + realm + ", " + path);
             ResourceTypeIdentifier rti =3D getResourceTypeIdentifier(realm=
, path);
             ResourceConfiguration rc =3D new RTIbasedResourceConfiguration=
(rti);
-            return getResource(environment, realm, path, rc);
+            return rc; //TODO check null check!
         } =

 =

         // Check on resource configuration map
@@ -129,22 +143,23 @@
         if (rcPath !=3D null) {
             if (realm.getRTIRepository().existsNode(rcPath)) {
                 ResourceConfiguration rc =3D new ResourceConfiguration(rea=
lm.getRTIRepository().getNode(ResourceConfigurationMap.getRCPath(realm, pat=
h)));
-                if (rc !=3D null) return getResource(environment, realm, p=
ath, rc);
+                return rc; //TODO check null check!
             } else {
                 throw new Exception("Request did match within resource con=
figuration map of realm '" + realm.getName() + "', but no such resource typ=
e configuration node exist: " + rcPath);
             }
         } =

         =

-        // Fallback to file/node resource
-        return getResource(environment, realm, path, new ResourceConfigura=
tion("file", "http://www.wyona.org/yanel/resource/1.0", null));
+        // Fallback to file/node resource configuration
+        return new ResourceConfiguration("file", "http://www.wyona.org/yan=
el/resource/1.0", null);
         =

     }
 =

     /**
      * Returns the abstraction of the rti file for the given path in the r=
ealm.
      * TODO: move this method to some RTIManager class ?
-     * @deprecated
+     * @deprecated Use {@link #getResourceConfiguration(Environment, Realm=
, String)} instead.
      */
+    @Deprecated
     public ResourceTypeIdentifier getResourceTypeIdentifier(Realm realm, S=
tring path) throws Exception {
         log.debug("Original path: " + path);
         try {
Index: src/impl/java/org/wyona/yanel/impl/ResourceTypeDefaultMatcher.java
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/impl/java/org/wyona/yanel/impl/ResourceTypeDefaultMatcher.java	(Rev=
ision 0)
+++ src/impl/java/org/wyona/yanel/impl/ResourceTypeDefaultMatcher.java	(Rev=
ision 0)
@@ -0,0 +1,23 @@
+package org.wyona.yanel.impl;
+
+import java.util.Map;
+
+import org.wyona.yanel.core.Environment;
+import org.wyona.yanel.core.ResourceConfiguration;
+import org.wyona.yanel.core.ResourceManager;
+import org.wyona.yanel.core.api.ResourceTypeMatcherV1;
+import org.wyona.yanel.core.map.Realm;
+
+public class ResourceTypeDefaultMatcher implements ResourceTypeMatcherV1 {
+
+    private static final ResourceManager rm =3D new ResourceManager();
+
+    public ResourceConfiguration getResourceConfiguration(Environment envi=
ronment, Realm realm, String path) throws Exception {
+        // TODO handle parameters
+        Map<String, String> parameterMap =3D (Map<String, String>) environ=
ment.getRequest().getParameterMap();
+
+        //throw new UnsupportedOperationException();
+        return rm.getResourceConfiguration(environment, realm, path);
+    }
+
+}
Index: src/core/java/org/wyona/yanel/core/api/ResourceTypeMatcherV1.java
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/core/java/org/wyona/yanel/core/api/ResourceTypeMatcherV1.java	(Revi=
sion 0)
+++ src/core/java/org/wyona/yanel/core/api/ResourceTypeMatcherV1.java	(Revi=
sion 0)
@@ -0,0 +1,11 @@
+package org.wyona.yanel.core.api;
+
+import org.wyona.yanel.core.Environment;
+import org.wyona.yanel.core.ResourceConfiguration;
+import org.wyona.yanel.core.map.Realm;
+
+public interface ResourceTypeMatcherV1 {
+
+    public ResourceConfiguration getResourceConfiguration(Environment envi=
ronment, Realm realm, String path) throws Exception;
+
+}
Index: src/webapp/src/java/org/wyona/yanel/servlet/YanelGlobalResourceTypeM=
atcher.java
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/webapp/src/java/org/wyona/yanel/servlet/YanelGlobalResourceTypeMatc=
her.java	(Revision 45854)
+++ src/webapp/src/java/org/wyona/yanel/servlet/YanelGlobalResourceTypeMatc=
her.java	(Arbeitskopie)
@@ -8,9 +8,10 @@
 import org.apache.commons.io.IOUtils;
 import org.wyona.yanel.core.Environment;
 import org.wyona.yanel.core.ResourceConfiguration;
+import org.wyona.yanel.core.api.ResourceTypeMatcherV1;
 import org.wyona.yanel.core.map.Realm;
 =

-class YanelGlobalResourceTypeMatcher {
+class YanelGlobalResourceTypeMatcher implements ResourceTypeMatcherV1 {
 =

     private String pathPrefix;
     private String globalRCsBasePath;
Index: src/webapp/src/java/org/wyona/yanel/servlet/YanelServlet.java
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/webapp/src/java/org/wyona/yanel/servlet/YanelServlet.java	(Revision=
 45854)
+++ src/webapp/src/java/org/wyona/yanel/servlet/YanelServlet.java	(Arbeitsk=
opie)
@@ -38,6 +38,7 @@
 import org.wyona.yanel.core.ResourceConfiguration;
 import org.wyona.yanel.core.ResourceTypeRegistry;
 import org.wyona.yanel.core.Yanel;
+import org.wyona.yanel.core.api.ResourceTypeMatcherV1;
 import org.wyona.yanel.core.api.attributes.IntrospectableV1;
 import org.wyona.yanel.core.api.attributes.ModifiableV1;
 import org.wyona.yanel.core.api.attributes.ModifiableV2;
@@ -1635,7 +1636,7 @@
         Realm realm;
         Environment environment =3D getEnvironment(request, response);
         ResourceConfiguration rc;
-        YanelGlobalResourceTypeMatcher RTmatcher =3D new YanelGlobalResour=
ceTypeMatcher(pathPrefix, servletContextRealPath);
+        ResourceTypeMatcherV1 RTmatcher =3D new YanelGlobalResourceTypeMat=
cher(pathPrefix, servletContextRealPath);
         try {
             realm =3D getRealm(request);
             rc =3D RTmatcher.getResourceConfiguration(environment, realm, =
path);


More information about the Yanel-development mailing list