/* * JBoss, Home of Professional Open Source * Copyright 2006, 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. */ package org.jboss.deployers.client.spi; import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; /** * IncompleteDeployments. * * @author <a href="adrian@jboss.com">Adrian Brock</a> * @version $Revision: 1.1 $ */ public class IncompleteDeployments implements Serializable { /** The serialVersionUID */ private static final long serialVersionUID = -8413355643801749950L; /** Deployments in error */ private Map<String, Throwable> deploymentsInError; /** Deployments missing deployer */ private Collection<String> deploymentsMissingDeployer; /** Contexts in error */ private Map<String, Throwable> contextsInError; /** Contexts missing dependencies */ private Map<String, Set<MissingDependency>> contextsMissingDependencies; /** Deployments in error info */ private String deploymentsInErrorInfo; /** Missing deployers info */ private String deploymentsMissingDeployerInfo; /** Contexts in error info */ private String contextsInErrorInfo; /** Contexts missing dependencies info */ private String contextsMissingDependenciesInfo; /** * Create a new IncompleteDeploymentException. * * @param deploymentsInError deployments in error * @param deploymentsMissingDeployer deployments missing deployer * @param contextsInError contexts in error * @param contextsMissingDependencies contexts missing dependencies */ public IncompleteDeployments(Map<String, Throwable> deploymentsInError, Collection<String> deploymentsMissingDeployer, Map<String, Throwable> contextsInError, Map<String, Set<MissingDependency>> contextsMissingDependencies) { if (deploymentsInError != null && deploymentsInError.isEmpty() == false) { this.deploymentsInError = new TreeMap<String, Throwable>(); this.deploymentsInError.putAll(deploymentsInError); } if (deploymentsMissingDeployer != null && deploymentsMissingDeployer.isEmpty() == false) { this.deploymentsMissingDeployer = new TreeSet<String>(); this.deploymentsMissingDeployer.addAll(deploymentsMissingDeployer); } if (contextsInError != null && contextsInError.isEmpty() == false) { this.contextsInError = new TreeMap<String, Throwable>(); this.contextsInError.putAll(contextsInError); } if (contextsMissingDependencies != null && contextsMissingDependencies.isEmpty() == false) { this.contextsMissingDependencies = new TreeMap<String, Set<MissingDependency>>(); this.contextsMissingDependencies.putAll(contextsMissingDependencies); } } /** * Whether it is incomplete * * @return true when incomplete */ public boolean isIncomplete() { if (deploymentsInError != null) return true; if (deploymentsMissingDeployer != null ) return true; if (contextsInError != null) return true; if (contextsMissingDependencies != null) return true; return false; } /** * Whether deployment unit is responsible for incomplete deployment. * * @param deploymentName deployment unit name * @return true when deployment unit is responsible */ public boolean isInvalidDeployment(String deploymentName) { if (isIncomplete() == false) return false; if (matchComponentName(deploymentName, getDeploymentsInError().keySet())) return true; if (matchComponentName(deploymentName, getDeploymentsMissingDeployer())) return true; return false; } /** * Whether context is responsible for incomplete deployment. * * @param contextName context's name * @return true when context is responsible */ public boolean isInvalidContext(String contextName) { if (isIncomplete() == false) return false; if (matchComponentName(contextName, getContextsInError().keySet())) return true; if (matchComponentName(contextName, getContextsMissingDependencies().keySet())) return true; return false; } /** * Get the info about deployments in error. * * @return string info */ public String getDeploymentsInErrorInfo() { if (deploymentsInErrorInfo == null) { StringBuilder buffer = new StringBuilder(); // Display all the incomplete deployments Map<String, Throwable> deploymentsInError = getDeploymentsInError(); if (deploymentsInError.isEmpty() == false) { buffer.append("\n*** DEPLOYMENTS IN ERROR: Name -> Error\n\n"); for (Map.Entry<String, Throwable> entry : deploymentsInError.entrySet()) buffer.append(entry.getKey()).append(" -> ").append(entry.getValue().toString()).append("\n\n"); } deploymentsInErrorInfo = buffer.toString(); } return deploymentsInErrorInfo; } /** * Get the info about missing deployers. * * @return string info */ public String getDeploymentsMissingDeployerInfo() { if (deploymentsMissingDeployerInfo == null) { StringBuilder buffer = new StringBuilder(); // Display all the missing deployers Collection<String> deploymentsMissingDeployers = getDeploymentsMissingDeployer(); if (deploymentsMissingDeployers.isEmpty() == false) { buffer.append("\n*** DEPLOYMENTS MISSING DEPLOYERS: Name\n\n"); for (String name : deploymentsMissingDeployers) buffer.append(name).append('\n'); } deploymentsMissingDeployerInfo = buffer.toString(); } return deploymentsMissingDeployerInfo; } /** * Merge root causes for the same key. * * @param rootCauses the root causes map * @param key the possible root cause key * @param value the possible root cause value */ private static void mergeRootCauses(Map<String, Set<String>> rootCauses, String key, String value) { Set<String> values = rootCauses.get(key); if (values == null) { values = Collections.singleton(value); rootCauses.put(key, values); } else { values = new HashSet<String>(values); values.add(value); rootCauses.put(key, values); } } /** * Calculate upfront context errors. */ protected void calculateContextsError() { // Popluate the potential root causes Map<String, Set<String>> rootCauses = new HashMap<String, Set<String>>(); // Missing dependencies are root causes Map<String, Set<MissingDependency>> contextsMissingDependencies = getContextsMissingDependencies(); if (contextsMissingDependencies.isEmpty() == false) { for (Map.Entry<String, Set<MissingDependency>> entry : contextsMissingDependencies.entrySet()) { for (MissingDependency dependency : entry.getValue()) mergeRootCauses(rootCauses, dependency.getDependency(), dependency.getActualState()); } } // Errors are root causes Map<String, Throwable> contextsInError = getContextsInError(); if (contextsInError.isEmpty() == false) { for (Map.Entry<String, Throwable> entry : contextsInError.entrySet()) { Throwable t = entry.getValue(); if (t == null) mergeRootCauses(rootCauses, entry.getKey(), "** UNKNOWN ERROR **"); else mergeRootCauses(rootCauses, entry.getKey(), t.toString()); } } StringBuilder buffer = new StringBuilder(); // Display all the missing dependencies if (contextsMissingDependencies.isEmpty() == false) { buffer.append("\n*** CONTEXTS MISSING DEPENDENCIES: Name -> Dependency{Required State:Actual State}\n\n"); for (Map.Entry<String, Set<MissingDependency>> entry : contextsMissingDependencies.entrySet()) { String name = entry.getKey(); buffer.append(name).append("\n"); for (MissingDependency dependency : entry.getValue()) { buffer.append(" -> ").append(dependency.getDependency()); buffer.append('{').append(dependency.getRequiredState()); buffer.append(':').append(dependency.getActualState()).append("}"); buffer.append("\n"); } buffer.append('\n'); // It is not a root cause if it has missing dependencies rootCauses.remove(name); } } contextsMissingDependenciesInfo = buffer.toString(); // reset buffer buffer.setLength(0); if (rootCauses.isEmpty() == false) { buffer.append("\n*** CONTEXTS IN ERROR: Name -> Error\n\n"); for (String key : rootCauses.keySet()) { buffer.append(key).append(" -> "); Set<String> values = rootCauses.get(key); boolean first = true; for (String value : values) { if (first == false) buffer.append(" | "); else first = false; buffer.append(value); } buffer.append("\n\n"); } } contextsInErrorInfo = buffer.toString(); } /** * Get the contexts in error info. * * @return string info */ public String getContextsInErrorInfo() { if (contextsInErrorInfo == null) calculateContextsError(); return contextsInErrorInfo; } /** * Get the contexts missing dependecies info * * @return the contexts missing dependency */ public String getContextsMissingDependenciesInfo() { if (contextsMissingDependenciesInfo == null) calculateContextsError(); return contextsMissingDependenciesInfo; } /** * Search for componentName in strings. * * @param componentName component's name * @param strings collection of strings * @return true if strings contains component name */ protected boolean matchComponentName(String componentName, Collection<String> strings) { return strings.contains(componentName); } /** * Get the contextsInError. * * @return the contextsInError. */ public Map<String, Throwable> getContextsInError() { if (contextsInError == null) return Collections.emptyMap(); else return Collections.unmodifiableMap(contextsInError); } /** * Get the contextsMissingDependencies. * * @return the contextsMissingDependencies. */ public Map<String, Set<MissingDependency>> getContextsMissingDependencies() { if (contextsMissingDependencies == null) return Collections.emptyMap(); else return Collections.unmodifiableMap(contextsMissingDependencies); } /** * Get the deploymentsInError. * * @return the deploymentsInError. */ public Map<String, Throwable> getDeploymentsInError() { if (deploymentsInError == null) return Collections.emptyMap(); else return Collections.unmodifiableMap(deploymentsInError); } /** * Get the deploymentsMissingDeployer. * * @return the deploymentsMissingDeployer. */ public Collection<String> getDeploymentsMissingDeployer() { if (deploymentsMissingDeployer == null) return Collections.emptySet(); else return Collections.unmodifiableCollection(deploymentsMissingDeployer); } }