Author: remy.maucherat(a)jboss.com
Date: 2009-05-19 12:56:51 -0400 (Tue, 19 May 2009)
New Revision: 1057
Modified:
trunk/ROADMAP.txt
trunk/java/org/apache/catalina/Globals.java
trunk/java/org/apache/catalina/startup/ContextConfig.java
trunk/java/org/apache/catalina/startup/LocalStrings.properties
trunk/java/org/apache/catalina/startup/WebRuleSet.java
trunk/java/org/apache/naming/resources/JARDirContext.java
trunk/java/org/apache/naming/resources/ProxyDirContext.java
Log:
- Add first pass at overlay support.
Modified: trunk/ROADMAP.txt
===================================================================
--- trunk/ROADMAP.txt 2009-05-15 16:25:46 UTC (rev 1056)
+++ trunk/ROADMAP.txt 2009-05-19 16:56:51 UTC (rev 1057)
@@ -1,7 +1,6 @@
Roadmap for JBoss Web 3.0
Standalone:
-- Resources overlay implementation
- Jasper plugins for TLD metadata and web.xml metadata
- Access control annotations
- Update digester XML parsing rules for web.xml updates (session tracking-mode,
cookie-config, servlet enabled,
Modified: trunk/java/org/apache/catalina/Globals.java
===================================================================
--- trunk/java/org/apache/catalina/Globals.java 2009-05-15 16:25:46 UTC (rev 1056)
+++ trunk/java/org/apache/catalina/Globals.java 2009-05-19 16:56:51 UTC (rev 1057)
@@ -343,7 +343,7 @@
* The folder used for JAR overlays.
*/
public static final String OVERLAY_PATH =
- System.getProperty("org.apache.catalina.OVERLAY_PATH",
"/META-INF/resources/");
+ System.getProperty("org.apache.catalina.OVERLAY_PATH",
"/META-INF/resources");
/**
Modified: trunk/java/org/apache/catalina/startup/ContextConfig.java
===================================================================
--- trunk/java/org/apache/catalina/startup/ContextConfig.java 2009-05-15 16:25:46 UTC (rev
1056)
+++ trunk/java/org/apache/catalina/startup/ContextConfig.java 2009-05-19 16:56:51 UTC (rev
1057)
@@ -109,6 +109,8 @@
import org.apache.catalina.deploy.WebAbsoluteOrdering;
import org.apache.catalina.deploy.WebOrdering;
import org.apache.catalina.util.StringManager;
+import org.apache.naming.resources.JARDirContext;
+import org.apache.naming.resources.ProxyDirContext;
import org.apache.tomcat.WarComponents;
import org.apache.tomcat.util.digester.Digester;
import org.apache.tomcat.util.digester.RuleSet;
@@ -588,7 +590,11 @@
}
- // FIXME: Do TLD parsing when found ? (clarification from EG states there's no
order)
+
+ /**
+ * Parse TLDs. This is separate, and is not subject to the order defined. Also,
+ * all TLDs from all JARs are parsed.
+ */
protected void applicationTldConfig() {
// Add all TLDs from explicit web config
@@ -1155,13 +1161,11 @@
scanClasses(explodedJars[i], "", !context.getIgnoreAnnotations());
}
+ // Parse web fragment according to order
Iterator<String> orderIterator = order.iterator();
while (orderIterator.hasNext()) {
String jar = orderIterator.next();
JarFile jarFile = jarRepository.findJar(jar);
-
- // Parse web fragment according to order
- // FIXME: Merging rules
InputStream is = null;
ZipEntry entry = jarFile.getEntry(Globals.WEB_FRAGMENT_PATH);
if (entry != null) {
@@ -1196,14 +1200,15 @@
}
}
}
-
+ // Scan the JAR for TLDs and annotations
scanJar(jarFile, true);
}
- // Process any Jar not in the order, without annotations
+ // Process any Jar not in the order
JarFile[] jarFiles = jarRepository.findJars();
for (int i = 0; i < jarFiles.length; i++) {
if (!order.contains(jarFiles[i].getName())) {
+ // Scan the JAR for TLDs only
scanJar(jarFiles[i], false);
}
}
@@ -1831,18 +1836,28 @@
authenticatorConfig();
}
- // Find and configure webapp overlays
+ // Find and configure overlays
if (ok) {
JarRepository jarRepository = context.getJarRepository();
JarFile[] jars = jarRepository.findJars();
for (int i = 0; i < jars.length; i++) {
if (jars[i].getEntry(Globals.OVERLAY_PATH) != null) {
+ if (context.getResources() instanceof ProxyDirContext) {
+ ProxyDirContext resources = (ProxyDirContext)
context.getResources();
+ JARDirContext overlay = new JARDirContext();
+ overlay.setJarFile(jars[i], Globals.OVERLAY_PATH);
+ resources.addOverlay(overlay);
+ } else {
+ // Error, overlays need a ProxyDirContext to compose results
+ log.error(sm.getString("contextConfig.noOverlay",
jars[i].getName()));
+ ok = false;
+ }
overlays.add(jars[i].getName());
}
}
}
- // Make our application available if no problems were encountered
+ // Make our application unavailable if problems were encountered
if (!ok) {
log.error(sm.getString("contextConfig.unavailable"));
context.setConfigured(false);
Modified: trunk/java/org/apache/catalina/startup/LocalStrings.properties
===================================================================
--- trunk/java/org/apache/catalina/startup/LocalStrings.properties 2009-05-15 16:25:46 UTC
(rev 1056)
+++ trunk/java/org/apache/catalina/startup/LocalStrings.properties 2009-05-19 16:56:51 UTC
(rev 1057)
@@ -24,6 +24,7 @@
contextConfig.init=ContextConfig: Initializing
contextConfig.invalidAbsoluteOrder=Invalid absolute order
contextConfig.missingRealm=No Realm has been configured to authenticate against
+contextConfig.noOverlay=Overlay used in {0} requires a ProxyDirContext in the context
contextConfig.role.auth=WARNING: Security role name {0} used in an
<auth-constraint> without being defined in a <security-role>
contextConfig.role.link=WARNING: Security role name {0} used in a <role-link>
without being defined in a <security-role>
contextConfig.role.runas=WARNING: Security role name {0} used in a <run-as> without
being defined in a <security-role>
Modified: trunk/java/org/apache/catalina/startup/WebRuleSet.java
===================================================================
--- trunk/java/org/apache/catalina/startup/WebRuleSet.java 2009-05-15 16:25:46 UTC (rev
1056)
+++ trunk/java/org/apache/catalina/startup/WebRuleSet.java 2009-05-19 16:56:51 UTC (rev
1057)
@@ -1,18 +1,46 @@
/*
- * 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
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
*
- *
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.
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 1999-2009 The Apache Software Foundation
+ *
+ * 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.
*/
@@ -44,6 +72,7 @@
*
* @author Craig R. McClanahan
* @version $Revision$ $Date$
+ * FIXME: this needs to implement merging rules
*/
public class WebRuleSet extends RuleSetBase {
Modified: trunk/java/org/apache/naming/resources/JARDirContext.java
===================================================================
--- trunk/java/org/apache/naming/resources/JARDirContext.java 2009-05-15 16:25:46 UTC (rev
1056)
+++ trunk/java/org/apache/naming/resources/JARDirContext.java 2009-05-19 16:56:51 UTC (rev
1057)
@@ -148,11 +148,6 @@
* Set the JAR file from which data will be read.
*
* @param jarFile The JAR file
- *
- * @exception IllegalArgumentException if the specified value is not
- * supported by this implementation
- * @exception IllegalArgumentException if this would create a
- * malformed URL
*/
public void setJarFile(JarFile jarFile, String prefix) {
@@ -162,6 +157,9 @@
(sm.getString("resources.null"));
this.prefix = prefix;
+ if (prefix.startsWith("/")) {
+ this.prefix = prefix.substring(1);
+ }
this.base = jarFile;
loadEntries();
@@ -214,8 +212,6 @@
*/
public Object lookup(Name name)
throws NamingException {
- //if (prefixName != null)
- // name.addAll(0, prefixName);
if (name.isEmpty())
return this;
Entry entry = treeLookup(name);
@@ -301,8 +297,6 @@
*/
public NamingEnumeration list(Name name)
throws NamingException {
- //if (prefixName != null)
- // name.addAll(0, prefixName);
if (name.isEmpty())
return new NamingContextEnumeration(list(entries).iterator());
Entry entry = treeLookup(name);
@@ -347,8 +341,6 @@
*/
public NamingEnumeration listBindings(Name name)
throws NamingException {
- //if (prefixName != null)
- // name.addAll(0, prefixName);
if (name.isEmpty())
return new NamingContextBindingsEnumeration(list(entries).iterator(),
this);
@@ -464,9 +456,6 @@
public Attributes getAttributes(Name name, String[] attrIds)
throws NamingException {
- //if (prefixName != null)
- // name.addAll(0, prefixName);
-
Entry entry = null;
if (name.isEmpty())
entry = entries;
@@ -741,37 +730,6 @@
/**
- * Add a prefix.
- */
- protected String prefix(String path) {
- if (prefix == null) {
- return path;
- } else if (path.startsWith("/")) {
- return prefix + path;
- } else {
- return prefix + "/" + path;
- }
- }
-
-
- /**
- * Remove a prefix.
- */
- protected String unprefix(String path) {
- if (prefix == null) {
- return path;
- } else if (path.startsWith("/")) {
- if (path.startsWith(prefix)) {
-
- }
- return prefix + path;
- } else {
- return prefix + "/" + path;
- }
- }
-
-
- /**
* Normalize the name of an entry read from the Zip.
*/
protected String normalize(ZipEntry entry) {
@@ -803,7 +761,6 @@
// Don't create entries for everything in the JAR if there is a
prefix
continue;
}
- name = name.substring(prefix.length());
int pos = name.lastIndexOf('/');
// Check that parent entries exist and, if not, create them.
// This fixes a bug for war files that don't record separate
@@ -811,8 +768,8 @@
int currentPos = -1;
int lastPos = 0;
while ((currentPos = name.indexOf('/', lastPos)) != -1) {
- Name parentName = new CompositeName(name.substring(0, lastPos));
- Name childName = new CompositeName(name.substring(0, currentPos));
+ Name parentName = new CompositeName(name.substring(prefix.length(),
lastPos));
+ Name childName = new CompositeName(name.substring(prefix.length(),
currentPos));
String entryName = name.substring(lastPos, currentPos);
// Parent should have been created in last cycle through
// this loop
@@ -824,7 +781,7 @@
// normalize method and add '/' character to end to
// signify that it is a directory entry
String zipName = name.substring(1, currentPos) + "/";
- child = new Entry(entryName, new JarEntry(prefix + zipName));
+ child = new Entry(entryName, new JarEntry(zipName));
if (parent != null)
parent.addChild(child);
}
Modified: trunk/java/org/apache/naming/resources/ProxyDirContext.java
===================================================================
--- trunk/java/org/apache/naming/resources/ProxyDirContext.java 2009-05-15 16:25:46 UTC
(rev 1056)
+++ trunk/java/org/apache/naming/resources/ProxyDirContext.java 2009-05-19 16:56:51 UTC
(rev 1057)
@@ -49,22 +49,32 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.HashMap;
import java.util.Hashtable;
import javax.naming.Binding;
import javax.naming.Context;
import javax.naming.Name;
+import javax.naming.NameAlreadyBoundException;
import javax.naming.NameClassPair;
import javax.naming.NameNotFoundException;
import javax.naming.NameParser;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
+import javax.naming.NotContextException;
+import javax.naming.OperationNotSupportedException;
+import javax.naming.directory.AttributeModificationException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
+import javax.naming.directory.InvalidAttributesException;
+import javax.naming.directory.InvalidSearchControlsException;
+import javax.naming.directory.InvalidSearchFilterException;
import javax.naming.directory.ModificationItem;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
+import org.apache.naming.NamingContextBindingsEnumeration;
+import org.apache.naming.NamingContextEnumeration;
import org.apache.naming.StringManager;
/**
@@ -149,7 +159,7 @@
/**
* Overlay DirContexts.
*/
- protected DirContext[] overlayDirContexts;
+ protected DirContext[] overlays = null;
/**
@@ -247,6 +257,20 @@
return this.contextName;
}
+
+ /**
+ * Add overlay.
+ */
+ public void addOverlay(DirContext overlay) {
+ if (overlays == null) {
+ overlays = new DirContext[0];
+ }
+ DirContext[] result = new DirContext[overlays.length + 1];
+ System.arraycopy(overlays, 0, result, 0, overlays.length);
+ result[overlays.length] = overlay;
+ overlays = result;
+ }
+
// -------------------------------------------------------- Context Methods
@@ -474,10 +498,53 @@
* this context. Each element of the enumeration is of type NameClassPair.
* @exception NamingException if a naming exception is encountered
*/
- // FIXME: Should use overlays
public NamingEnumeration<NameClassPair> list(Name name)
throws NamingException {
- return dirContext.list(parseName(name));
+ if (overlays == null) {
+ return dirContext.list(parseName(name));
+ } else {
+ NamingException notFound = null;
+ HashMap<String, NameClassPair> merged = null;
+ NamingEnumeration<NameClassPair> main = null;
+ try {
+ main = dirContext.list(parseName(name));
+ } catch (NamingException e) {
+ notFound = e;
+ }
+ for (int i = 0; i < overlays.length; i++) {
+ NamingEnumeration<NameClassPair> overlay = null;
+ try {
+ overlay = overlays[i].list(parseName(name));
+ } catch (NamingException e) {
+ // Ignore
+ }
+ if (main == null) {
+ main = overlay;
+ } else {
+ // Merge that into the merged set
+ if (merged == null) {
+ merged = new HashMap<String, NameClassPair>();
+ while (main.hasMore()) {
+ NameClassPair pair = main.next();
+ merged.put(pair.getName(), pair);
+ }
+ }
+ while (overlay.hasMore()) {
+ NameClassPair pair = overlay.next();
+ if (merged.get(pair.getName()) == null) {
+ merged.put(pair.getName(), pair);
+ }
+ }
+ }
+ }
+ if (main == null && merged == null) {
+ throw notFound;
+ } else if (merged != null) {
+ return new NamingContextEnumeration(merged.values().iterator());
+ } else {
+ return main;
+ }
+ }
}
@@ -490,10 +557,53 @@
* this context. Each element of the enumeration is of type NameClassPair.
* @exception NamingException if a naming exception is encountered
*/
- // FIXME: Should use overlays
public NamingEnumeration<NameClassPair> list(String name)
throws NamingException {
- return dirContext.list(parseName(name));
+ if (overlays == null) {
+ return dirContext.list(parseName(name));
+ } else {
+ NamingException notFound = null;
+ HashMap<String, NameClassPair> merged = null;
+ NamingEnumeration<NameClassPair> main = null;
+ try {
+ main = dirContext.list(parseName(name));
+ } catch (NamingException e) {
+ notFound = e;
+ }
+ for (int i = 0; i < overlays.length; i++) {
+ NamingEnumeration<NameClassPair> overlay = null;
+ try {
+ overlay = overlays[i].list(parseName(name));
+ } catch (NamingException e) {
+ // Ignore
+ }
+ if (main == null) {
+ main = overlay;
+ } else {
+ // Merge that into the merged set
+ if (merged == null) {
+ merged = new HashMap<String, NameClassPair>();
+ while (main.hasMore()) {
+ NameClassPair pair = main.next();
+ merged.put(pair.getName(), pair);
+ }
+ }
+ while (overlay.hasMore()) {
+ NameClassPair pair = overlay.next();
+ if (merged.get(pair.getName()) == null) {
+ merged.put(pair.getName(), pair);
+ }
+ }
+ }
+ }
+ if (main == null && merged == null) {
+ throw notFound;
+ } else if (merged != null) {
+ return new NamingContextEnumeration(merged.values().iterator());
+ } else {
+ return main;
+ }
+ }
}
@@ -510,10 +620,53 @@
* Each element of the enumeration is of type Binding.
* @exception NamingException if a naming exception is encountered
*/
- // FIXME: Should use overlays
public NamingEnumeration<Binding> listBindings(Name name)
throws NamingException {
- return dirContext.listBindings(parseName(name));
+ if (overlays == null) {
+ return dirContext.listBindings(parseName(name));
+ } else {
+ NamingException notFound = null;
+ HashMap<String, Binding> merged = null;
+ NamingEnumeration<Binding> main = null;
+ try {
+ main = dirContext.listBindings(parseName(name));
+ } catch (NamingException e) {
+ notFound = e;
+ }
+ for (int i = 0; i < overlays.length; i++) {
+ NamingEnumeration<Binding> overlay = null;
+ try {
+ overlay = overlays[i].listBindings(parseName(name));
+ } catch (NamingException e) {
+ // Ignore
+ }
+ if (main == null) {
+ main = overlay;
+ } else {
+ // Merge that into the merged set
+ if (merged == null) {
+ merged = new HashMap<String, Binding>();
+ while (main.hasMore()) {
+ Binding pair = main.next();
+ merged.put(pair.getName(), pair);
+ }
+ }
+ while (overlay.hasMore()) {
+ Binding pair = overlay.next();
+ if (merged.get(pair.getName()) == null) {
+ merged.put(pair.getName(), pair);
+ }
+ }
+ }
+ }
+ if (main == null && merged == null) {
+ throw notFound;
+ } else if (merged != null) {
+ return new NamingContextBindingsEnumeration(merged.values().iterator(),
this);
+ } else {
+ return main;
+ }
+ }
}
@@ -526,10 +679,53 @@
* Each element of the enumeration is of type Binding.
* @exception NamingException if a naming exception is encountered
*/
- // FIXME: Should use overlays
public NamingEnumeration<Binding> listBindings(String name)
throws NamingException {
- return dirContext.listBindings(parseName(name));
+ if (overlays == null) {
+ return dirContext.listBindings(parseName(name));
+ } else {
+ NamingException notFound = null;
+ HashMap<String, Binding> merged = null;
+ NamingEnumeration<Binding> main = null;
+ try {
+ main = dirContext.listBindings(parseName(name));
+ } catch (NamingException e) {
+ notFound = e;
+ }
+ for (int i = 0; i < overlays.length; i++) {
+ NamingEnumeration<Binding> overlay = null;
+ try {
+ overlay = overlays[i].listBindings(parseName(name));
+ } catch (NamingException e) {
+ // Ignore
+ }
+ if (main == null) {
+ main = overlay;
+ } else {
+ // Merge that into the merged set
+ if (merged == null) {
+ merged = new HashMap<String, Binding>();
+ while (main.hasMore()) {
+ Binding pair = main.next();
+ merged.put(pair.getName(), pair);
+ }
+ }
+ while (overlay.hasMore()) {
+ Binding pair = overlay.next();
+ if (merged.get(pair.getName()) == null) {
+ merged.put(pair.getName(), pair);
+ }
+ }
+ }
+ }
+ if (main == null && merged == null) {
+ throw notFound;
+ } else if (merged != null) {
+ return new NamingContextBindingsEnumeration(merged.values().iterator(),
this);
+ } else {
+ return main;
+ }
+ }
}
@@ -1529,10 +1725,10 @@
/**
* Load entry into cache.
*/
- // FIXME: Should use overlays
protected void cacheLoad(CacheEntry entry) {
String name = entry.name;
+ DirContext currentContext = dirContext;
// Retrieve missing info
boolean exists = true;
@@ -1540,7 +1736,7 @@
// Retrieving attributes
if (entry.attributes == null) {
try {
- Attributes attributes = dirContext.getAttributes(entry.name);
+ Attributes attributes = currentContext.getAttributes(entry.name);
if (!(attributes instanceof ResourceAttributes)) {
entry.attributes =
new ResourceAttributes(attributes);
@@ -1551,11 +1747,30 @@
exists = false;
}
}
+
+ // Check overlays
+ if (overlays != null) {
+ for (int i = 0; (i < overlays.length) && !exists; i++) {
+ try {
+ Attributes attributes = overlays[i].getAttributes(entry.name);
+ if (!(attributes instanceof ResourceAttributes)) {
+ entry.attributes =
+ new ResourceAttributes(attributes);
+ } else {
+ entry.attributes = (ResourceAttributes) attributes;
+ }
+ currentContext = overlays[i];
+ exists = true;
+ } catch (NamingException e) {
+ // Ignore
+ }
+ }
+ }
// Retriving object
if ((exists) && (entry.resource == null) && (entry.context ==
null)) {
try {
- Object object = dirContext.lookup(name);
+ Object object = currentContext.lookup(name);
if (object instanceof InputStream) {
entry.resource = new Resource((InputStream) object);
} else if (object instanceof DirContext) {
@@ -1610,7 +1825,12 @@
entry.exists = exists;
// Set timestamp
- entry.timestamp = System.currentTimeMillis() + cacheTTL;
+ if (currentContext == dirContext) {
+ entry.timestamp = System.currentTimeMillis() + cacheTTL;
+ } else {
+ // Overlay cache never expire
+ entry.timestamp = Long.MAX_VALUE;
+ }
// Add new entry to cache
synchronized (cache) {