| /* |
| * 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. |
| */ |
| |
| package org.apache.axis2.clustering.state; |
| |
| import org.apache.axis2.clustering.ClusteringFault; |
| import org.apache.axis2.clustering.state.commands.DeleteServiceGroupStateCommand; |
| import org.apache.axis2.clustering.state.commands.StateClusteringCommandCollection; |
| import org.apache.axis2.clustering.state.commands.UpdateConfigurationStateCommand; |
| import org.apache.axis2.clustering.state.commands.UpdateServiceGroupStateCommand; |
| import org.apache.axis2.clustering.state.commands.UpdateServiceStateCommand; |
| import org.apache.axis2.clustering.state.commands.UpdateStateCommand; |
| import org.apache.axis2.context.AbstractContext; |
| import org.apache.axis2.context.ConfigurationContext; |
| import org.apache.axis2.context.PropertyDifference; |
| import org.apache.axis2.context.ServiceContext; |
| import org.apache.axis2.context.ServiceGroupContext; |
| import org.apache.axis2.deployment.DeploymentConstants; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.ObjectOutputStream; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * |
| */ |
| public final class StateClusteringCommandFactory { |
| |
| private static final Log log = LogFactory.getLog(StateClusteringCommandFactory.class); |
| |
| public static StateClusteringCommandCollection |
| getCommandCollection(AbstractContext[] contexts, |
| Map excludedReplicationPatterns) { |
| |
| ArrayList<StateClusteringCommand> commands = new ArrayList<StateClusteringCommand>(contexts.length); |
| StateClusteringCommandCollection collection = |
| new StateClusteringCommandCollection(commands); |
| for (AbstractContext context : contexts) { |
| StateClusteringCommand cmd = getUpdateCommand(context, |
| excludedReplicationPatterns, |
| false); |
| if (cmd != null) { |
| commands.add(cmd); |
| } |
| } |
| return collection; |
| } |
| |
| /** |
| * @param context The context |
| * @param excludedPropertyPatterns The property patterns to be excluded |
| * @param includeAllProperties True - Include all properties, |
| * False - Include only property differences |
| * @return ContextClusteringCommand |
| */ |
| public static StateClusteringCommand getUpdateCommand(AbstractContext context, |
| Map excludedPropertyPatterns, |
| boolean includeAllProperties) { |
| |
| UpdateStateCommand cmd = toUpdateContextCommand(context); |
| if (cmd != null) { |
| fillProperties(cmd, |
| context, |
| excludedPropertyPatterns, |
| includeAllProperties); |
| if (cmd.isPropertiesEmpty()) { |
| cmd = null; |
| } |
| } |
| return cmd; |
| } |
| |
| |
| public static StateClusteringCommand getUpdateCommand(AbstractContext context, |
| String[] propertyNames) |
| throws ClusteringFault { |
| |
| UpdateStateCommand cmd = toUpdateContextCommand(context); |
| if (cmd != null) { |
| fillProperties(cmd, context, propertyNames); |
| if (cmd.isPropertiesEmpty()) { |
| cmd = null; |
| } |
| } |
| return cmd; |
| } |
| |
| private static UpdateStateCommand toUpdateContextCommand(AbstractContext context) { |
| UpdateStateCommand cmd = null; |
| if (context instanceof ConfigurationContext) { |
| cmd = new UpdateConfigurationStateCommand(); |
| } else if (context instanceof ServiceGroupContext) { |
| ServiceGroupContext sgCtx = (ServiceGroupContext) context; |
| cmd = new UpdateServiceGroupStateCommand(); |
| UpdateServiceGroupStateCommand updateSgCmd = (UpdateServiceGroupStateCommand) cmd; |
| updateSgCmd.setServiceGroupName(sgCtx.getDescription().getServiceGroupName()); |
| updateSgCmd.setServiceGroupContextId(sgCtx.getId()); |
| } else if (context instanceof ServiceContext) { |
| ServiceContext serviceCtx = (ServiceContext) context; |
| cmd = new UpdateServiceStateCommand(); |
| UpdateServiceStateCommand updateServiceCmd = (UpdateServiceStateCommand) cmd; |
| String sgName = |
| serviceCtx.getServiceGroupContext().getDescription().getServiceGroupName(); |
| updateServiceCmd.setServiceGroupName(sgName); |
| updateServiceCmd.setServiceGroupContextId(serviceCtx.getServiceGroupContext().getId()); |
| updateServiceCmd.setServiceName(serviceCtx.getAxisService().getName()); |
| } |
| return cmd; |
| } |
| |
| /** |
| * @param updateCmd The command |
| * @param context The context |
| * @param excludedPropertyPatterns The property patterns to be excluded from replication |
| * @param includeAllProperties True - Include all properties, |
| * False - Include only property differences |
| */ |
| private static void fillProperties(UpdateStateCommand updateCmd, |
| AbstractContext context, |
| Map excludedPropertyPatterns, |
| boolean includeAllProperties) { |
| if (!includeAllProperties) { |
| synchronized (context) { |
| Map diffs = context.getPropertyDifferences(); |
| for (Object o : diffs.keySet()) { |
| String key = (String) o; |
| PropertyDifference diff = (PropertyDifference) diffs.get(key); |
| Object value = diff.getValue(); |
| if (isSerializable(value)) { |
| |
| // Next check whether it matches an excluded pattern |
| if (!isExcluded(key, |
| context.getClass().getName(), |
| excludedPropertyPatterns)) { |
| if (log.isDebugEnabled()) { |
| log.debug("sending property =" + key + "-" + value); |
| } |
| updateCmd.addProperty(diff); |
| } |
| } |
| } |
| } |
| } else { |
| synchronized (context) { |
| for (Iterator iter = context.getPropertyNames(); iter.hasNext();) { |
| String key = (String) iter.next(); |
| Object value = context.getPropertyNonReplicable(key); |
| if (isSerializable(value)) { |
| |
| // Next check whether it matches an excluded pattern |
| if (!isExcluded(key, context.getClass().getName(), excludedPropertyPatterns)) { |
| if (log.isDebugEnabled()) { |
| log.debug("sending property =" + key + "-" + value); |
| } |
| PropertyDifference diff = new PropertyDifference(key, value, false); |
| updateCmd.addProperty(diff); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| private static void fillProperties(UpdateStateCommand updateCmd, |
| AbstractContext context, |
| String[] propertyNames) throws ClusteringFault { |
| Map diffs = context.getPropertyDifferences(); |
| for (String key : propertyNames) { |
| Object prop = context.getPropertyNonReplicable(key); |
| |
| // First check whether it is serializable |
| if (isSerializable(prop)) { |
| if (log.isDebugEnabled()) { |
| log.debug("sending property =" + key + "-" + prop); |
| } |
| PropertyDifference diff = (PropertyDifference) diffs.get(key); |
| if (diff != null) { |
| diff.setValue(prop); |
| updateCmd.addProperty(diff); |
| |
| // Remove the diff? |
| diffs.remove(key); |
| } |
| } else { |
| String msg = |
| "Trying to replicate non-serializable property " + key + |
| " in context " + context; |
| throw new ClusteringFault(msg); |
| } |
| } |
| } |
| |
| private static boolean isExcluded(String propertyName, |
| String ctxClassName, |
| Map excludedPropertyPatterns) { |
| |
| // Check in the excludes list specific to the context |
| List specificExcludes = |
| (List) excludedPropertyPatterns.get(ctxClassName); |
| boolean isExcluded = false; |
| if (specificExcludes != null) { |
| isExcluded = isExcluded(specificExcludes, propertyName); |
| } |
| if (!isExcluded) { |
| // check in the default excludes |
| List defaultExcludes = |
| (List) excludedPropertyPatterns.get(DeploymentConstants.TAG_DEFAULTS); |
| if (defaultExcludes != null) { |
| isExcluded = isExcluded(defaultExcludes, propertyName); |
| } |
| } |
| return isExcluded; |
| } |
| |
| private static boolean isExcluded(List list, String propertyName) { |
| for (Object aList : list) { |
| String pattern = (String) aList; |
| if (pattern.startsWith("*")) { |
| pattern = pattern.replaceAll("\\*", ""); |
| if (propertyName.endsWith(pattern)) { |
| return true; |
| } |
| } else if (pattern.endsWith("*")) { |
| pattern = pattern.replaceAll("\\*", ""); |
| if (propertyName.startsWith(pattern)) { |
| return true; |
| } |
| } else if (pattern.equals(propertyName)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public static StateClusteringCommand getRemoveCommand(AbstractContext abstractContext) { |
| if (abstractContext instanceof ServiceGroupContext) { |
| ServiceGroupContext sgCtx = (ServiceGroupContext) abstractContext; |
| DeleteServiceGroupStateCommand cmd = new DeleteServiceGroupStateCommand(); |
| cmd.setServiceGroupContextId(sgCtx.getId()); |
| |
| return cmd; |
| } |
| return null; |
| } |
| |
| private static boolean isSerializable(Object obj) { |
| try { |
| ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| ObjectOutputStream oos = new ObjectOutputStream(out); |
| oos.writeObject(obj); |
| oos.close(); |
| return out.toByteArray().length > 0; |
| } catch (Exception e) { |
| return false; |
| } |
| } |
| } |