/* * JBoss, Home of Professional Open Source. * Copyright 2008, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file 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.profileservice.management; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.jboss.deployers.client.spi.main.MainDeployer; import org.jboss.deployers.spi.management.DeploymentTemplate; import org.jboss.deployers.spi.management.ManagementView; import org.jboss.deployers.spi.management.NameMatcher; import org.jboss.deployers.spi.management.RuntimeComponentDispatcher; import org.jboss.logging.Logger; import org.jboss.managed.api.ComponentType; import org.jboss.managed.api.DeploymentTemplateInfo; import org.jboss.managed.api.Fields; import org.jboss.managed.api.ManagedComponent; import org.jboss.managed.api.ManagedDeployment; import org.jboss.managed.api.ManagedObject; import org.jboss.managed.api.ManagedOperation; import org.jboss.managed.api.ManagedProperty; import org.jboss.managed.api.annotation.ActivationPolicy; import org.jboss.managed.api.annotation.ViewUse; import org.jboss.metatype.api.values.MetaValue; import org.jboss.profileservice.management.views.AbstractProfileView; import org.jboss.profileservice.management.views.BootstrapProfileView; import org.jboss.profileservice.management.views.PlatformMbeansView; import org.jboss.profileservice.management.views.ProfileView; import org.jboss.profileservice.spi.NoSuchDeploymentException; import org.jboss.profileservice.spi.NoSuchProfileException; import org.jboss.profileservice.spi.Profile; import org.jboss.profileservice.spi.ProfileDeployment; import org.jboss.profileservice.spi.ProfileKey; import org.jboss.profileservice.spi.ProfileService; import org.jboss.system.server.profileservice.attachments.AttachmentStore; /** * A aggregating management view, handling profile views for all active profiles. * * @author <a href="mailto:emuckenh@redhat.com">Emanuel Muckenhuber</a> * @version $Revision$ */ public class AggregatingManagementView extends AbstractTemplateCreator implements ManagementView { /** The logger. */ private static final Logger log = Logger.getLogger(AggregatingManagementView.class); /** The bundle name. */ private static final String BUNDLE_NAME = "org.jboss.profileservice.management.messages"; /** The internationalization resource bundle. */ private ResourceBundle i18n; /** the Locale for the i18n messages. */ private Locale currentLocale; /** The formatter used for i18n messages. */ private MessageFormat formatter = new MessageFormat(""); /** The profile service. */ private ProfileService ps; /** The runtime component dispatcher. */ private RuntimeComponentDispatcher dispatcher; private ManagedOperationProxyFactory proxyFactory; /** The main deployer. */ private MainDeployer mainDeployer; /** The attachment store. */ private AttachmentStore store; /** The bootstrap deployment name to ManagedDeployment map. */ private Map<String, ManagedDeployment> bootstrapManagedDeployments = Collections.emptyMap(); /** The deployment templates that have been registered with the MV. */ private HashMap<String, DeploymentTemplate> templates = new HashMap<String, DeploymentTemplate>(); /** The profile views. */ private Map<ProfileKey, AbstractProfileView> profileViews = new ConcurrentHashMap<ProfileKey, AbstractProfileView>(); public AggregatingManagementView() { currentLocale = Locale.getDefault(); formatter.setLocale(currentLocale); i18n = ResourceBundle.getBundle(BUNDLE_NAME, currentLocale); } public RuntimeComponentDispatcher getDispatcher() { return dispatcher; } public void setDispatcher(RuntimeComponentDispatcher dispatcher) { this.dispatcher = dispatcher; } public ProfileService getProfileService() { return ps; } public void setProfileService(ProfileService ps) { this.ps = ps; } public ManagedOperationProxyFactory getProxyFactory() { return proxyFactory; } public void setProxyFactory(ManagedOperationProxyFactory proxyFactory) { this.proxyFactory = proxyFactory; } public AttachmentStore getAttachmentStore() { return store; } public void setAttachmentStore(AttachmentStore store) { this.store = store; } public MainDeployer getMainDeployer() { return mainDeployer; } public void setMainDeployer(MainDeployer mainDeployer) { this.mainDeployer = mainDeployer; } public Map<String, ManagedDeployment> getBootstrapManagedDeployments() { return bootstrapManagedDeployments; } public void setBootstrapManagedDeployments(Map<String, ManagedDeployment> bootstrapManagedDeployments) { this.bootstrapManagedDeployments = bootstrapManagedDeployments; } public void start() throws Exception { if(this.proxyFactory == null) throw new IllegalStateException("proxy factory not injected"); // Add the platform MBeans addView(new PlatformMbeansView(this.proxyFactory)); // Add the bootstrap deployments if(this.bootstrapManagedDeployments != null) { addView(new BootstrapProfileView(this.proxyFactory, this.bootstrapManagedDeployments.values())); } } public boolean load() { return loadProfiles(false); } public void reload() { loadProfiles(true); } public void process() throws Exception { // FIXME process } public void addView(AbstractProfileView view) { if(view == null) throw new IllegalArgumentException("null view"); if(view.getProfileKey() == null) throw new IllegalArgumentException("null profile key"); this.profileViews.put(view.getProfileKey(), view); log.debug("add view: " + view); } public void removeView(AbstractProfileView view) { if(view == null) throw new IllegalArgumentException("null view"); if(view.getProfileKey() == null) throw new IllegalArgumentException("null profile key"); this.profileViews.remove(view.getProfileKey()); log.debug("remove view: " + view); } public void addTemplate(DeploymentTemplate template) { this.templates.put(template.getInfo().getName(), template); log.debug("addTemplate: " + template); } public void removeTemplate(DeploymentTemplate template) { this.templates.remove(template.getInfo().getName()); log.debug("removeTemplate: " + template); } public void applyTemplate(String deploymentBaseName, DeploymentTemplateInfo info) throws Exception { if(deploymentBaseName == null) throw new IllegalArgumentException("Null deployment base name."); if(info == null) throw new IllegalArgumentException("Null template info."); DeploymentTemplate template = templates.get(info.getName()); if( template == null ) { formatter.applyPattern(i18n.getString("ManagementView.NoSuchTemplate")); Object[] args = {info.getName()}; String msg = formatter.format(args); throw new IllegalStateException(msg); } // Create a deployment base from the template if( log.isTraceEnabled() ) log.trace("applyTemplate, deploymentBaseName=" + deploymentBaseName + ", info=" + info); // Apply the template super.applyTemplate(template, deploymentBaseName, info); // reload this profile this.profileViews.put(getDefaulProfiletKey(), createProfileView(getDefaulProfiletKey())); } public ManagedComponent getComponent(String name, ComponentType type) throws Exception { Set<ManagedComponent> components = getComponentsForType(type); ManagedComponent comp = null; if(components != null) { for(ManagedComponent mc : components) { if(mc.getName().equals(name)) { comp = mc; break; } } } if(comp != null) { Map<String, ManagedProperty> props = comp.getProperties(); Set<ManagedOperation> ops = comp.getOperations(); log.debug("Component" +"(ops.size=" +ops != null ? ops.size() : 0 +",props.size=)" +props != null ? props.size() : 0); } return comp; } public Set<ComponentType> getComponentTypes() { Set<ComponentType> componentTypes = new HashSet<ComponentType>(); for(AbstractProfileView view : profileViews.values()) { componentTypes.addAll(view.getComponentTypes()); } return componentTypes; } public Set<ManagedComponent> getComponentsForType(ComponentType type) throws Exception { Set<ManagedComponent> components = new HashSet<ManagedComponent>(); for(AbstractProfileView view : profileViews.values()) { components.addAll(view.getComponentsForType(type)); } return components; } public ManagedDeployment getDeployment(String name) throws NoSuchDeploymentException { List<ManagedDeployment> deployments = new ArrayList<ManagedDeployment>(); for(AbstractProfileView view : profileViews.values()) { deployments.addAll(view.getDeployment(name)); } if(deployments.size() == 0) { throw new NoSuchDeploymentException(name); } else if(deployments.size() > 1) { throw new NoSuchDeploymentException("multiple matching deployments found for name: " + name + ", available: " + deployments); } return deployments.get(0); } public Set<String> getDeploymentNames() { Set<String> deploymentNames = new TreeSet<String>(); for(AbstractProfileView view : profileViews.values()) { deploymentNames.addAll(view.getDeploymentNames()); } return deploymentNames; } public Set<String> getDeploymentNamesForType(String type) { Set<String> deploymentNames = new TreeSet<String>(); for(AbstractProfileView view : profileViews.values()) { deploymentNames.addAll(view.getDeploymentNamesForType(type)); } return deploymentNames; } public Set<ManagedDeployment> getDeploymentsForType(String type) throws Exception { Set<ManagedDeployment> deployments = new HashSet<ManagedDeployment>(); for(AbstractProfileView view : profileViews.values()) { deployments.addAll(view.getDeploymentsForType(type)); } return deployments; } public Set<ManagedComponent> getMatchingComponents(String name, ComponentType type, NameMatcher<ManagedComponent> matcher) throws Exception { Set<ManagedComponent> components = getComponentsForType(type); Set<ManagedComponent> matched = new HashSet<ManagedComponent>(); if(components != null) { for(ManagedComponent mc : components) { if(matcher.matches(mc, name)) matched.add(mc); } } if(matched.size() > 0) { log.debug("getComponents matched: "+matched); } return matched; } public Set<String> getMatchingDeploymentName(String regex) throws NoSuchDeploymentException { Set<String> names = getDeploymentNames(); HashSet<String> matches = new HashSet<String>(); Pattern p = Pattern.compile(regex); for(String name : names) { Matcher m = p.matcher(name); if( m.matches() ) matches.add(name); } if( matches.size() == 0 ) { formatter.applyPattern(i18n.getString("ManagementView.NoSuchDeploymentException")); //$NON-NLS-1$ Object[] args = {regex}; String msg = formatter.format(args); throw new NoSuchDeploymentException(msg); } return matches; } public Set<ManagedDeployment> getMatchingDeployments(String name, NameMatcher<ManagedDeployment> matcher) throws NoSuchDeploymentException, Exception { // FIXME getMatchingDeployments return new HashSet<ManagedDeployment>(); } public DeploymentTemplateInfo getTemplate(String name) throws NoSuchDeploymentException { DeploymentTemplate template = templates.get(name); if( template == null ) { formatter.applyPattern(i18n.getString("ManagementView.NoSuchTemplate")); //$NON-NLS-1$ Object[] args = {name}; String msg = formatter.format(args); throw new IllegalStateException(msg); } // Make sure to return a copy to avoid call by reference uses modifying the template values DeploymentTemplateInfo info = template.getInfo(); info = info.copy(); log.debug("getTemplate, "+info); return info; } public Set<String> getTemplateNames() { return new HashSet<String>(templates.keySet()); } public void removeComponent(ManagedComponent comp) throws Exception { if(comp == null) throw new IllegalArgumentException("null managed component."); // ManagedDeployment md = comp.getDeployment(); // Get the parent while( md.getParent() != null ) md = md.getParent(); String name = md.getName(); ProfileDeployment profileDeployment = getProfileDeployment(name); if( profileDeployment == null ) { formatter.applyPattern(i18n.getString("ManagementView.NoSuchDeploymentException")); //$NON-NLS-1$ Object[] args = {name}; String msg = formatter.format(args); throw new NoSuchDeploymentException(msg); } // Apply the managed properties to the server ManagedDeployment/ManagedComponent ManagedDeployment compMD = getDeployment(md.getName()); log.debug("updateComponent, deploymentName="+name+": "+compMD); ManagedComponent serverComp = null; // Find the managed component again if(comp.getDeployment().getParent() == null) { serverComp = compMD.getComponent(comp.getName()); } else { // Look at the children // TODO - support more levels of nested deployments ? if(compMD.getChildren() != null && compMD.getChildren().isEmpty() == false) { for(ManagedDeployment child : compMD.getChildren()) { if(serverComp != null) break; serverComp = child.getComponent(comp.getName()); } } } if(serverComp == null) { log.debug("Name: "+comp.getName()+" does not map to existing ManagedComponet in ManagedDeployment: "+md.getName() + ", components: "+compMD.getComponents()); formatter.applyPattern(i18n.getString("ManagementView.InvalidComponentName")); //$NON-NLS-1$ Object[] args = {comp.getName(), md.getName()}; String msg = formatter.format(args); throw new IllegalArgumentException(msg); } // log.debug("remove component: " + comp + ", deployment: "+ profileDeployment); // Remove Profile profile = getProfileForDeployment(md.getName()); this.store.removeComponent(comp.getDeployment().getName(), serverComp); this.profileViews.put(profile.getKey(), createProfileView(profile)); } public void updateComponent(ManagedComponent comp) throws Exception { if(comp == null) throw new IllegalArgumentException("Null managed component."); // Find the comp deployment ManagedDeployment md = comp.getDeployment(); // Get the parent while( md.getParent() != null ) md = md.getParent(); String name = md.getName(); ProfileDeployment compDeployment = getProfileDeployment(name); if( compDeployment == null ) { formatter.applyPattern(i18n.getString("ManagementView.NoSuchDeploymentException")); //$NON-NLS-1$ Object[] args = {name}; String msg = formatter.format(args); throw new NoSuchDeploymentException(msg); } // Apply the managed properties to the server ManagedDeployment/ManagedComponent ManagedDeployment compMD = getDeployment(md.getName()); log.debug("updateComponent, deploymentName="+name+": "+compMD); ManagedComponent serverComp = null; // Find the managed component again if(comp.getDeployment().getParent() == null) { serverComp = compMD.getComponent(comp.getName()); } else { // Look at the children // TODO - support more levels of nested deployments ? if(compMD.getChildren() != null && compMD.getChildren().isEmpty() == false) { for(ManagedDeployment child : compMD.getChildren()) { if(serverComp != null) break; serverComp = child.getComponent(comp.getName()); } } } if(serverComp == null) { log.debug("Name: "+comp.getName()+" does not map to existing ManagedComponet in ManagedDeployment: " + md.getName() + ", components: "+compMD.getComponents()); formatter.applyPattern(i18n.getString("ManagementView.InvalidComponentName")); //$NON-NLS-1$ Object[] args = {comp.getName(), md.getName()}; String msg = formatter.format(args); throw new IllegalArgumentException(msg); } // Dispatch any runtime component property values for(ManagedProperty prop : comp.getProperties().values()) { // Skip null values && non-CONFIGURATION values, unmodified values, and removed values boolean skip = prop.getValue() == null || prop.isReadOnly() || prop.hasViewUse(ViewUse.CONFIGURATION) == false // || prop.isModified() == false || prop.isRemoved() == true; if( skip ) { if(log.isTraceEnabled()) log.trace("Skipping component property: "+prop); continue; } ManagedProperty ctxProp = serverComp.getProperties().get(prop.getName()); // Check for a mapped name if( ctxProp == null ) { String mappedName = prop.getMappedName(); if( mappedName != null ) ctxProp = serverComp.getProperties().get(mappedName); } if( ctxProp == null ) { formatter.applyPattern(i18n.getString("ManagementView.InvalidTemplateProperty")); //$NON-NLS-1$ Object[] args = {prop.getName()}; String msg = formatter.format(args); throw new IllegalArgumentException(msg); } // The property value must be a MetaValue Object value = prop.getValue(); if ((value instanceof MetaValue) == false) { formatter.applyPattern(i18n.getString("ManagementView.InvalidPropertyValue")); //$NON-NLS-1$ Object[] args = {prop.getName(), value.getClass()}; String msg = formatter.format(args); throw new IllegalArgumentException(msg); } // Update the serverComp MetaValue metaValue = (MetaValue)value; ctxProp.setField(Fields.META_TYPE, metaValue.getMetaType()); ctxProp.setValue(metaValue); // Dispatch any runtime component property values Object componentName = getComponentName(ctxProp); ActivationPolicy policy = ctxProp.getActivationPolicy(); if (componentName != null && policy.equals(ActivationPolicy.IMMEDIATE)) { AbstractRuntimeComponentDispatcher.setActiveProperty(ctxProp); dispatcher.set(componentName, ctxProp.getName(), metaValue); } } // Persist the changed values Profile profile = getProfileForDeployment(md.getName()); this.store.updateDeployment(comp.getDeployment().getName(), serverComp); this.profileViews.put(profile.getKey(), createProfileView(profile)); } protected boolean loadProfiles(boolean forceReload) { boolean wasReloaded = false; Collection<ProfileKey> activeProfiles = ps.getActiveProfileKeys(); for(ProfileKey key : activeProfiles) { if(loadProfile(key, forceReload)) wasReloaded = true; } return wasReloaded; } protected boolean loadProfile(ProfileKey key, boolean forceReload) { boolean wasModified = false; try { // The active profile Profile profile = ps.getActiveProfile(key); AbstractProfileView view = this.profileViews.get(profile.getKey()); // Check if we need to reload the profile wasModified = forceReload || view == null || view.hasBeenModified(profile); if(wasModified) { this.profileViews.put(key, createProfileView(profile)); wasModified = true; } } catch(NoSuchProfileException e) { wasModified = profileViews.remove(key) != null; log.debug("Failed to load profile " + key); } return wasModified; } protected AbstractProfileView createProfileView(ProfileKey key) throws NoSuchProfileException { Profile profile = this.ps.getActiveProfile(key); return createProfileView(profile); } protected AbstractProfileView createProfileView(Profile profile) { return new ProfileView(profile, proxyFactory, mainDeployer); } protected Object getComponentName(ManagedProperty property) { // first check target ManagedObject targetObject = property.getTargetManagedObject(); if (targetObject != null) return targetObject.getComponentName(); // check owner targetObject = property.getManagedObject(); return targetObject != null ? targetObject.getComponentName() : null; } private ProfileKey getProfileKeyForDeployemnt(String name) throws NoSuchDeploymentException { ManagedDeployment md = getDeployment(name); return md.getAttachment(ProfileKey.class); } private Profile getProfileForDeployment(String name) throws Exception { ProfileKey key = getProfileKeyForDeployemnt(name); if(key == null) throw new NoSuchDeploymentException("No associated profile found for deployment:" + name); return this.ps.getActiveProfile(key); } private ProfileDeployment getProfileDeployment(String name) throws Exception { Profile profile = getProfileForDeployment(name); return profile.getDeployment(name); } }