[jboss-cvs] JBossAS SVN: r93222 - trunk/server/src/main/org/jboss/web/deployers.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Sat Sep 5 14:48:59 EDT 2009
Author: remy.maucherat at jboss.com
Date: 2009-09-05 14:48:59 -0400 (Sat, 05 Sep 2009)
New Revision: 93222
Modified:
trunk/server/src/main/org/jboss/web/deployers/MergedJBossWebMetaDataDeployer.java
Log:
- Add the fragment order resolution code from Catalina.
Modified: trunk/server/src/main/org/jboss/web/deployers/MergedJBossWebMetaDataDeployer.java
===================================================================
--- trunk/server/src/main/org/jboss/web/deployers/MergedJBossWebMetaDataDeployer.java 2009-09-05 17:11:23 UTC (rev 93221)
+++ trunk/server/src/main/org/jboss/web/deployers/MergedJBossWebMetaDataDeployer.java 2009-09-05 18:48:59 UTC (rev 93222)
@@ -21,17 +21,33 @@
*/
package org.jboss.web.deployers;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
import org.jboss.deployers.spi.DeploymentException;
import org.jboss.deployers.spi.deployer.DeploymentStages;
import org.jboss.deployers.spi.deployer.helpers.AbstractDeployer;
import org.jboss.deployers.structure.spi.DeploymentUnit;
+import org.jboss.deployers.vfs.spi.structure.VFSDeploymentUnit;
import org.jboss.deployment.AnnotationMetaDataDeployer;
import org.jboss.metadata.ear.jboss.JBossAppMetaData;
+import org.jboss.metadata.javaee.spec.SecurityRolesMetaData;
+import org.jboss.metadata.web.jboss.JBossWebMetaData;
+import org.jboss.metadata.web.spec.AbsoluteOrderingMetaData;
import org.jboss.metadata.web.spec.AnnotationMergedView;
-import org.jboss.metadata.web.jboss.JBossWebMetaData;
+import org.jboss.metadata.web.spec.OrderingElementMetaData;
import org.jboss.metadata.web.spec.Web25MetaData;
+import org.jboss.metadata.web.spec.Web30MetaData;
+import org.jboss.metadata.web.spec.WebFragmentMetaData;
import org.jboss.metadata.web.spec.WebMetaData;
-import org.jboss.metadata.javaee.spec.SecurityRolesMetaData;
+import org.jboss.virtual.VirtualFile;
/**
* A deployer that merges annotation metadata, xml metadata, and jboss metadata
@@ -45,6 +61,7 @@
public class MergedJBossWebMetaDataDeployer extends AbstractDeployer
{
public static final String WEB_MERGED_ATTACHMENT_NAME = "merged."+JBossWebMetaData.class.getName();
+ public static final String WEB_ORDER_ATTACHMENT_NAME = "order."+WebMetaData.class.getName();
/**
* Create a new MergedJBossWebMetaDataDeployer.
@@ -62,6 +79,7 @@
setOutput(JBossWebMetaData.class);
//
addOutput(WEB_MERGED_ATTACHMENT_NAME);
+ addOutput(WEB_ORDER_ATTACHMENT_NAME);
}
public void deploy(DeploymentUnit unit) throws DeploymentException
@@ -71,9 +89,194 @@
if(specMetaData == null && metaData == null)
return;
- // FIXME: Check for a deployment order
+ // FIXME: Check metadata-complete (see AnnotationMetaDataDeployer)
+ // Find all fragments that have been processed by deployers, and place them in a map keyed by location
+ LinkedList<String> order = new LinkedList<String>();
+ List<WebOrdering> orderings = new ArrayList<WebOrdering>();
+ HashSet<String> jarsSet = new HashSet<String>();
+ VirtualFile webInfLib = null;
+ boolean fragmentFound = false;
+ HashMap<String, WebFragmentMetaData> webFragments = new HashMap<String, WebFragmentMetaData>();
+ if (unit instanceof VFSDeploymentUnit)
+ {
+ VFSDeploymentUnit vfsUnit = (VFSDeploymentUnit) unit;
+ webInfLib = vfsUnit.getFile("WEB-INF/lib");
+ if (webInfLib != null)
+ {
+ try
+ {
+ List<VirtualFile> jars = webInfLib.getChildren();
+ for (VirtualFile jar : jars)
+ {
+ jarsSet.add(jar.getName());
+ }
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ String base = unit.getName();
+ int pos = base.indexOf(':');
+ if (pos > 0)
+ {
+ base = base.substring(pos);
+ }
+
+ Iterator<String> attachementNames = unit.getAttachments().keySet().iterator();
+ HashSet<String> jarsWithoutFragmentsSet = (HashSet<String>) jarsSet.clone();
+ while (attachementNames.hasNext())
+ {
+ String location = attachementNames.next();
+ Object attachement = unit.getAttachment(location);
+ if (attachement != null && attachement instanceof WebFragmentMetaData)
+ {
+ pos = location.indexOf(':');
+ if (pos > 0)
+ {
+ location = location.substring(pos);
+ }
+ if (!location.startsWith(base))
+ {
+ // If there is only one fragment, it will also get mapped as this attachement
+ continue;
+ }
+ String relativeLocation = "/" + location.substring(base.length());
+ String jarName = null;
+ if (relativeLocation.startsWith("/WEB-INF/lib/"))
+ {
+ jarName = relativeLocation.substring("/WEB-INF/lib/".length());
+ }
+ if (jarName == null)
+ {
+ continue;
+ }
+ fragmentFound = true;
+ WebFragmentMetaData fragmentMetaData = (WebFragmentMetaData) attachement;
+ webFragments.put(jarName, fragmentMetaData);
+ WebOrdering webOrdering = new WebOrdering();
+ webOrdering.setName(fragmentMetaData.getName());
+ webOrdering.setJar(jarName);
+ jarsWithoutFragmentsSet.remove(jarName);
+ if (fragmentMetaData.getOrdering() != null)
+ {
+ if (fragmentMetaData.getOrdering().getAfter() != null)
+ {
+ for (OrderingElementMetaData orderingElementMetaData :
+ fragmentMetaData.getOrdering().getAfter().getOrdering())
+ {
+ if (orderingElementMetaData.isOthers())
+ {
+ webOrdering.setAfterOthers(true);
+ }
+ else
+ {
+ webOrdering.addAfter(orderingElementMetaData.getName());
+ }
+ }
+ }
+ if (fragmentMetaData.getOrdering().getBefore() != null)
+ {
+ for (OrderingElementMetaData orderingElementMetaData :
+ fragmentMetaData.getOrdering().getBefore().getOrdering())
+ {
+ if (orderingElementMetaData.isOthers())
+ {
+ webOrdering.setBeforeOthers(true);
+ }
+ else
+ {
+ webOrdering.addBefore(orderingElementMetaData.getName());
+ }
+ }
+ }
+ }
+ orderings.add(webOrdering);
+ }
+ }
+ // If there is no fragment, still consider it for ordering as a
+ // fragment specifying no name and no order
+ for (String jarName : jarsWithoutFragmentsSet)
+ {
+ WebOrdering ordering = new WebOrdering();
+ ordering.setJar(jarName);
+ orderings.add(ordering);
+ }
+ }
+
+ if (!fragmentFound)
+ {
+ // Drop the order as there is no fragment in the webapp
+ orderings.clear();
+ }
+
+ // Generate web fragments parsing order
+ AbsoluteOrderingMetaData absoluteOrderingMetaData = null;
+ if (specMetaData instanceof Web30MetaData)
+ {
+ absoluteOrderingMetaData = ((Web30MetaData) specMetaData).getAbsoluteOrdering();
+ }
+ if (absoluteOrderingMetaData != null) {
+ // Absolute ordering from web.xml, any relative fragment ordering is ignored
+ int otherPos = -1;
+ int i = 0;
+ for (OrderingElementMetaData orderingElementMetaData : absoluteOrderingMetaData.getOrdering())
+ {
+ if (orderingElementMetaData.isOthers())
+ {
+ if (otherPos >= 0) {
+ throw new DeploymentException("Duplicate others in absolute ordering");
+ }
+ otherPos = i;
+ }
+ else
+ {
+ for (WebOrdering ordering : orderings)
+ {
+ if (ordering.getName().equals(orderingElementMetaData.getName())) {
+ order.add(ordering.getJar());
+ jarsSet.remove(ordering.getJar());
+ break;
+ }
+ }
+ }
+ i++;
+ }
+ if (otherPos >= 0)
+ {
+ order.addAll(otherPos, jarsSet);
+ }
+ }
+ else if (orderings.size() > 0)
+ {
+ // Resolve relative ordering
+ try
+ {
+ resolveOrder(orderings, order);
+ }
+ catch (IllegalStateException e)
+ {
+ DeploymentException.rethrowAsDeploymentException("Invalid ordering", e);
+ }
+ }
+ else
+ {
+ // No order specified
+ order.addAll(jarsSet);
+ }
+
+ unit.addAttachment(WEB_ORDER_ATTACHMENT_NAME, order);
+
+ // The fragments and corresponding annotations will need to be merged in order
+ // 1: Merge specMetaData into mergedMetaData
+ // 2: For each JAR in the order:
+ // 2.1: Merge the fragment metadata into specMetaData, according to the Servlet 3.0 overriding rules
+ // 2.1: Merge the annotation metadata into specMetaData, according to the Servlet 3.0 overriding rules
+ // 3: Merge the Servlet annotations for all declared Servlets ?
+ // 4: Override with metaData (JBossWebMetaData)
+ // FIXME: Implement
+
// Check for an annotated view
String key = AnnotationMetaDataDeployer.WEB_ANNOTATED_ATTACHMENT_NAME;
Web25MetaData annotatedMetaData = unit.getAttachment(key, Web25MetaData.class);
@@ -123,4 +326,354 @@
unit.getTransientManagedObjects().addAttachment(JBossWebMetaData.class, mergedMetaData);
}
+
+ /**
+ * Utility class to associate the logical name with the JAR name, needed during the
+ * order resolving.
+ * @author remm
+ */
+ protected class WebOrdering implements Serializable {
+
+ private static final long serialVersionUID = 5603203103871892211L;
+
+ protected String jar = null;
+ protected String name = null;
+ protected List<String> after = new ArrayList<String>();
+ protected List<String> before = new ArrayList<String>();
+ protected boolean afterOthers = false;
+ protected boolean beforeOthers = false;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List<String> getAfter() {
+ return after;
+ }
+
+ public void addAfter(String name) {
+ after.add(name);
+ }
+
+ public List<String> getBefore() {
+ return before;
+ }
+
+ public void addBefore(String name) {
+ before.add(name);
+ }
+
+ public String getJar() {
+ return jar;
+ }
+
+ public void setJar(String jar) {
+ this.jar = jar;
+ }
+
+ public boolean isAfterOthers() {
+ return afterOthers;
+ }
+
+ public void setAfterOthers(boolean afterOthers) {
+ this.afterOthers = afterOthers;
+ }
+
+ public boolean isBeforeOthers() {
+ return beforeOthers;
+ }
+
+ public void setBeforeOthers(boolean beforeOthers) {
+ this.beforeOthers = beforeOthers;
+ }
+
+ }
+
+ protected static class Ordering {
+ protected WebOrdering ordering;
+ protected Set<Ordering> after = new HashSet<Ordering>();
+ protected Set<Ordering> before = new HashSet<Ordering>();
+ protected boolean afterOthers = false;
+ protected boolean beforeOthers = false;
+
+ public boolean addAfter(Ordering ordering) {
+ return after.add(ordering);
+ }
+
+ public boolean addBefore(Ordering ordering) {
+ return before.add(ordering);
+ }
+
+ public void validate() {
+ isBefore(new Ordering());
+ isAfter(new Ordering());
+ }
+
+ /**
+ * Check (recursively) if a fragment is before the specified fragment.
+ *
+ * @param ordering
+ * @return
+ */
+ public boolean isBefore(Ordering ordering) {
+ return isBeforeInternal(ordering, new HashSet<Ordering>());
+ }
+
+ protected boolean isBeforeInternal(Ordering ordering, Set<Ordering> checked) {
+ checked.add(this);
+ if (before.contains(ordering)) {
+ return true;
+ }
+ Iterator<Ordering> beforeIterator = before.iterator();
+ while (beforeIterator.hasNext()) {
+ Ordering check = beforeIterator.next();
+ if (checked.contains(check)) {
+ //throw new IllegalStateException(sm.getString("ordering.orderConflict", this.ordering.getJar()));
+ throw new IllegalStateException("Ordering conflict with JAR: " + this.ordering.getJar());
+ }
+ if (check.isBeforeInternal(ordering, checked)) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check (recursively) if a fragment is after the specified fragment.
+ *
+ * @param ordering
+ * @return
+ */
+ public boolean isAfter(Ordering ordering) {
+ return isAfterInternal(ordering, new HashSet<Ordering>());
+ }
+
+ protected boolean isAfterInternal(Ordering ordering, Set<Ordering> checked) {
+ checked.add(this);
+ if (after.contains(ordering)) {
+ return true;
+ }
+ Iterator<Ordering> afterIterator = after.iterator();
+ while (afterIterator.hasNext()) {
+ Ordering check = afterIterator.next();
+ if (checked.contains(check)) {
+ //throw new IllegalStateException(sm.getString("ordering.orderConflict", this.ordering.getJar()));
+ throw new IllegalStateException("Ordering conflict with JAR: " + this.ordering.getJar());
+ }
+ if (check.isAfterInternal(ordering, checked)) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check is a fragment marked as before others is after a fragment that is not.
+ *
+ * @return true if a fragment marked as before others is after a fragment that is not
+ */
+ public boolean isLastBeforeOthers() {
+ if (!beforeOthers) {
+ throw new IllegalStateException();
+ }
+ Iterator<Ordering> beforeIterator = before.iterator();
+ while (beforeIterator.hasNext()) {
+ Ordering check = beforeIterator.next();
+ if (!check.beforeOthers) {
+ return true;
+ } else if (check.isLastBeforeOthers()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check is a fragment marked as after others is before a fragment that is not.
+ *
+ * @return true if a fragment marked as after others is before a fragment that is not
+ */
+ public boolean isFirstAfterOthers() {
+ if (!afterOthers) {
+ throw new IllegalStateException();
+ }
+ Iterator<Ordering> afterIterator = after.iterator();
+ while (afterIterator.hasNext()) {
+ Ordering check = afterIterator.next();
+ if (!check.afterOthers) {
+ return true;
+ } else if (check.isFirstAfterOthers()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ }
+
+ /**
+ * Generate the Jar processing order.
+ *
+ * @param webOrderings The list of orderings, as parsed from the fragments
+ * @param order The generated order list
+ */
+ protected static void resolveOrder(List<WebOrdering> webOrderings, List<String> order) {
+ List<Ordering> work = new ArrayList<Ordering>();
+
+ // Populate the work Ordering list
+ Iterator<WebOrdering> webOrderingsIterator = webOrderings.iterator();
+ while (webOrderingsIterator.hasNext()) {
+ WebOrdering webOrdering = webOrderingsIterator.next();
+ Ordering ordering = new Ordering();
+ ordering.ordering = webOrdering;
+ ordering.afterOthers = webOrdering.isAfterOthers();
+ ordering.beforeOthers = webOrdering.isBeforeOthers();
+ if (ordering.afterOthers && ordering.beforeOthers) {
+ // Cannot be both after and before others
+ //throw new IllegalStateException(sm.getString("ordering.afterAndBeforeOthers", webOrdering.getJar()));
+ throw new IllegalStateException("Ordering includes both before and after others in JAR: " + webOrdering.getJar());
+ }
+ work.add(ordering);
+ }
+
+ // Create double linked relationships between the orderings,
+ // and resolve names
+ Iterator<Ordering> workIterator = work.iterator();
+ while (workIterator.hasNext()) {
+ Ordering ordering = workIterator.next();
+ WebOrdering webOrdering = ordering.ordering;
+ Iterator<String> after = webOrdering.getAfter().iterator();
+ while (after.hasNext()) {
+ String name = after.next();
+ Iterator<Ordering> workIterator2 = work.iterator();
+ boolean found = false;
+ while (workIterator2.hasNext()) {
+ Ordering ordering2 = workIterator2.next();
+ if (name.equals(ordering2.ordering.getName())) {
+ if (found) {
+ // Duplicate name
+ //throw new IllegalStateException(sm.getString("ordering.duplicateName", webOrdering.getJar()));
+ throw new IllegalStateException("Duplicate name declared in JAR: " + webOrdering.getJar());
+ }
+ ordering.addAfter(ordering2);
+ ordering2.addBefore(ordering);
+ found = true;
+ }
+ }
+ if (!found) {
+ // Unknown name
+ //throw new IllegalStateException(sm.getString("ordering.unkonwnName", webOrdering.getJar()));
+ throw new IllegalStateException("Unknown name declared in JAR: " + webOrdering.getJar());
+ }
+ }
+ Iterator<String> before = webOrdering.getBefore().iterator();
+ while (before.hasNext()) {
+ String name = before.next();
+ Iterator<Ordering> workIterator2 = work.iterator();
+ boolean found = false;
+ while (workIterator2.hasNext()) {
+ Ordering ordering2 = workIterator2.next();
+ if (name.equals(ordering2.ordering.getName())) {
+ if (found) {
+ // Duplicate name
+ //throw new IllegalStateException(sm.getString("ordering.duplicateName", webOrdering.getJar()));
+ throw new IllegalStateException("Duplicate name declared in JAR: " + webOrdering.getJar());
+ }
+ ordering.addBefore(ordering2);
+ ordering2.addAfter(ordering);
+ found = true;
+ }
+ }
+ if (!found) {
+ // Unknown name
+ //throw new IllegalStateException(sm.getString("ordering.unkonwnName", webOrdering.getJar()));
+ throw new IllegalStateException("Unknown name declared in JAR: " + webOrdering.getJar());
+ }
+ }
+ }
+
+ // Validate ordering
+ workIterator = work.iterator();
+ while (workIterator.hasNext()) {
+ workIterator.next().validate();
+ }
+
+ // Create three ordered lists that will then be merged
+ List<Ordering> tempOrder = new ArrayList<Ordering>();
+
+ // Create the ordered list of fragments which are before others
+ workIterator = work.iterator();
+ while (workIterator.hasNext()) {
+ Ordering ordering = workIterator.next();
+ if (ordering.beforeOthers) {
+ // Insert at the first possible position
+ int insertAfter = -1;
+ boolean last = ordering.isLastBeforeOthers();
+ int lastBeforeOthers = -1;
+ for (int i = 0; i < tempOrder.size(); i++) {
+ if (ordering.isAfter(tempOrder.get(i))) {
+ insertAfter = i;
+ }
+ if (tempOrder.get(i).beforeOthers) {
+ lastBeforeOthers = i;
+ }
+ }
+ int pos = insertAfter;
+ if (last && lastBeforeOthers > insertAfter) {
+ pos = lastBeforeOthers;
+ }
+ tempOrder.add(pos + 1, ordering);
+ } else if (ordering.afterOthers) {
+ // Insert at the last possible element
+ int insertBefore = tempOrder.size();
+ boolean first = ordering.isFirstAfterOthers();
+ int firstAfterOthers = tempOrder.size();
+ for (int i = tempOrder.size() - 1; i >= 0; i--) {
+ if (ordering.isBefore(tempOrder.get(i))) {
+ insertBefore = i;
+ }
+ if (tempOrder.get(i).afterOthers) {
+ firstAfterOthers = i;
+ }
+ }
+ int pos = insertBefore;
+ if (first && firstAfterOthers < insertBefore) {
+ pos = firstAfterOthers;
+ }
+ tempOrder.add(pos, ordering);
+ } else {
+ // Insert according to other already inserted elements
+ int insertAfter = -1;
+ int insertBefore = tempOrder.size();
+ for (int i = 0; i < tempOrder.size(); i++) {
+ if (ordering.isAfter(tempOrder.get(i)) || tempOrder.get(i).beforeOthers) {
+ insertAfter = i;
+ }
+ if (ordering.isBefore(tempOrder.get(i)) || tempOrder.get(i).afterOthers) {
+ insertBefore = i;
+ }
+ }
+ if (insertAfter > insertBefore) {
+ // Conflicting order (probably caught earlier)
+ //throw new IllegalStateException(sm.getString("ordering.orderConflict", ordering.ordering.getJar()));
+ throw new IllegalStateException("Fragment ordering conflict with JAR: " + ordering.ordering.getJar());
+ }
+ // Insert somewhere in the range
+ tempOrder.add(insertAfter + 1, ordering);
+ }
+ }
+
+ // Create the final ordered list
+ Iterator<Ordering> tempOrderIterator = tempOrder.iterator();
+ while (tempOrderIterator.hasNext()) {
+ Ordering ordering = tempOrderIterator.next();
+ order.add(ordering.ordering.getJar());
+ }
+
+ }
+
}
More information about the jboss-cvs-commits
mailing list