/*
* BEGIN_HEADER - DO NOT EDIT
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the "License"). You may not use this file except
* in compliance with the License.
*
* You can obtain a copy of the license at
* https://open-esb.dev.java.net/public/CDDLv1.0.html.
* See the License for the specific language governing
* permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* HEADER in each file and include the License file at
* https://open-esb.dev.java.net/public/CDDLv1.0.html.
* If applicable add the following below this CDDL HEADER,
* with the fields enclosed by brackets "[]" replaced with
* your own identifying information: Portions Copyright
* [year] [name of copyright owner]
*/
/*
* @(#)RegistryHelper.java
* Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
*
* END_HEADER - DO NOT EDIT
*/
/**
* RegistryHelper.java
*
* SUN PROPRIETARY/CONFIDENTIAL.
* This software is the proprietary information of Sun Microsystems, Inc.
* Use is subject to license terms.
*
* Created on January 2, 2006, 4:49 PM
*/
package com.sun.jbi.framework.sun;
import com.sun.jbi.StringTranslator;
import com.sun.jbi.ComponentInfo;
import com.sun.jbi.ComponentState;
import com.sun.jbi.ServiceAssemblyInfo;
import com.sun.jbi.ServiceAssemblyState;
import com.sun.jbi.platform.PlatformContext;
import com.sun.jbi.framework.EnvironmentContext;
import com.sun.jbi.framework.sun.LocalStringKeys;
import com.sun.jbi.management.ComponentInfo.Variable;
import com.sun.jbi.management.registry.GenericQuery;
import com.sun.jbi.management.registry.Registry;
import com.sun.jbi.management.registry.RegistryBuilder;
import com.sun.jbi.management.registry.RegistryDiff;
import com.sun.jbi.management.registry.RegistryException;
import com.sun.jbi.management.registry.RegistrySpecImpl;
import com.sun.jbi.management.registry.RegistryType;
import com.sun.jbi.management.MBeanNames;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.PrintStream;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
/*
* This class is a helper that hides the lower level details involved with
* getting remote files and diff'ing jbi registries.
*/
public class RegistryHelper
{
private static final String DOMAIN = "domain";
private static final String DAS_RELATIVE_PATH = "config";
private static final String STRING_TRANSLATOR_NAME = "com.sun.jbi.management.facade";
private static final String SL_KEY = "sl";
private static final String COMP_KEY = "comp";
private static final String SA_KEY = "sa";
private static final String DOMAIN_KEY = "domain";
private static final String INSTANCE_KEY = "instance";
private static final String STATIC_CONF_KEY = "static";
private static final String APPVAR_CONF_KEY = "appvar";
private static final String APPCON_CONF_KEY = "appcon";
private static final String JBI_SCHEMA_CONFIGS = "configs";
private static final String JBI_SCHEMA_CONFIG = "config";
private static final String JBI_SCHEMA_CONFIG_TYPE = "config-type";
private static final String JBI_SCHEMA_CATEGORY = "category";
private static final String JBI_SCHEMA_PROPERTY = "property";
private static final String JBI_SCHEMA_VALUE = "value";
private static final String JBI_SCHEMA_APPLICATION_VARIABLE = "application-variable";
private static final String JBI_SCHEMA_APPLICATION_CONFIGURATION = "application-configuration";
private static final String JBI_SCHEMA_COMPONENT = "component";
private static final String JBI_SCHEMA_COMPONENT_REF = "component-ref";
private static final String JBI_SCHEMA_COMPONENT_CONFIG = "component-config";
private static final String JBI_SCHEMA_SHARED_LIBRARY = "shared-library";
private static final String JBI_SCHEMA_SHARED_LIBRARY_REF = "shared-library-ref";
private static final String JBI_SCHEMA_SERVICE_ASSEMBLY = "service-assembly";
private static final String JBI_SCHEMA_SERVICE_ASSEMBLY_REF = "service-assembly-ref";
private static final String JBI_SCHEMA_SERVICE_UNIT = "service-unit";
private static final String JBI_SCHEMA_NAME = "name";
private static final String JBI_SCHEMA_NAME_REF = "name-ref";
private static final String JBI_SCHEMA_TIMESTAMP = "timestamp";
private static final String JBI_SCHEMA_STATE = "state";
private static final String JBI_SCHEMA_UPDATENUMBER = "upgrade-number";
static final int INITIALIZED = 1;
static final int SYNC_REQUIRED = 2;
static final int ALL_NOT_SHUTDOWN = 4;
private Registry mRegistry;
private Registry mMasterRegistry;
private String mDASRegistryFileName;
private String mSyncRegistryFileName;
private String mSyncFolder;
private RegistryDiff mDiff;
private Logger mLogger;
private String mTarget;
private PlatformContext mPlatform;
private StringTranslator mTranslator;
private ObjectName mDASDownloadMBeanName;
private MBeanServerConnection mMBeanServer;
private String mInstanceRootPath;
private HashMap mLocalReg;
private int mSyncState;
/**
* Constructor for new instance of the RegistryHelper.
* @param envCtx the environment context.
*/
public RegistryHelper(EnvironmentContext envCtx)
{
mPlatform = envCtx.getPlatformContext();
mTranslator = envCtx.getStringTranslator(STRING_TRANSLATOR_NAME);
mLogger = Logger.getLogger("com.sun.jbi.framework.sun");
mDASDownloadMBeanName = envCtx.getMBeanNames().getSystemServiceMBeanName(
MBeanNames.ServiceName.FileTransferService,
MBeanNames.ServiceType.Download, DOMAIN);
mInstanceRootPath = envCtx.getJbiInstanceRoot();
}
/**
* Determine if JBI needs to be started completely or if it can come up
* in a passive (i.e. initialized but not started) state. This determination
* is made by checking the desired state of components in the JBI registry.
* If all components are SHUTDOWN, then we can start in passive state and
* the framework will start system services on demand.
*/
public boolean isActiveStartup()
{
boolean isActive = true;
if (mPlatform.isAdminServer())
{
//
// On DAS we don't have to sync, but we do have to watch out for services
// that are not shutdown and may require XA recovery at restart.
//
if (allShutdown(getLocalRegInfo()))
{
isActive = false;
}
}
else
{
//
// More detailed check needed on instance.
//
if ((mSyncState & INITIALIZED) == 0)
{
computeXAActiveOrSyncRequired();
}
isActive = (mSyncState & ~INITIALIZED) != 0;
}
return isActive;
}
/**
* Determine if synchronization and/or XA recovery are required.
* Copy the master registry from the DAS.
* Open that master and the local and extract the information needed to answer the question.
* @return boolean containing the answer.
*/
private void computeXAActiveOrSyncRequired()
{
Exception e = null;
int result = 0;
try
{
HashMap syncReg;
HashMap localReg;
ByteArrayInputStream bais;
getDASDownloadMBeanServer();
mTarget = mPlatform.getTargetName();
syncReg = scanRegistry(bais = downloadRegistry());
localReg = getLocalRegInfo();
result = regMapsDiff(syncReg, localReg) |
(allShutdown(localReg) ? 0: ALL_NOT_SHUTDOWN) |
INITIALIZED;
/*
* If we are going to need the registry for synchronization, copy the registry from memory to
* a file.
*/
if ((result & SYNC_REQUIRED) != 0)
{
byte[] buffer = new byte[8192];
int count;
FileOutputStream fos;
bais.reset();
fos = new FileOutputStream(com.sun.jbi.util.EnvironmentAccess.getContext().getJbiInstanceRoot() + "/tmp/jbi-registry-sync.xml");
while ((count = bais.read(buffer)) > 0)
{
fos.write(buffer, 0, count);
}
fos.flush();
fos.close();
}
}
catch (SyncException sEx)
{
e = sEx;
}
catch (Exception ex)
{
e = ex;
}
if (e != null)
{
ByteArrayOutputStream b = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(b);
e.printStackTrace(ps);
ps.flush();
mLogger.info(mTranslator.getString(LocalStringKeys.JBI_SYNC_DAS_NOT_AVAILABLE));
mLogger.fine(mTranslator.getString(LocalStringKeys.JBI_SYNC_CHECK_FAILED , b.toString()));
}
mLogger.fine("JBI-Synchronization required state is: " + result);
mSyncState = result;
}
public boolean isSyncRequired()
{
return ((mSyncState & SYNC_REQUIRED) != 0);
}
void getDASDownloadMBeanServer()
{
//
// Get a connection to the DAS MBean Server for Synchronization downloads.
//
try
{
mMBeanServer = mPlatform.getMBeanServerConnection(mPlatform.getAdminServerName());
}
catch (Exception e)
{
mLogger.info(mTranslator.getString(LocalStringKeys.JBI_SYNC_DAS_NOT_AVAILABLE));
{
ByteArrayOutputStream baos = new ByteArrayOutputStream
();
PrintStream ps = new PrintStream(baos);
e.printStackTrace(ps);
ps.flush();
mLogger.fine(mTranslator.getString(LocalStringKeys.JBI_SYNC_DAS_FAILURE, baos.toString()));
}
}
}
/**
* Cleanup anything created by RegistryHelper.
*/
public void cleanup()
{
if (mMasterRegistry != null)
{
mMasterRegistry.destroy();
mMasterRegistry = null;
}
}
/**
* Get local registry information. The result is cached internally so repeated calls
* are cheap.
*/
synchronized HashMap getLocalRegInfo()
{
File reg;
if (mLocalReg == null)
{
try
{
Document regDoc = com.sun.jbi.util.EnvironmentAccess.getContext().getReadOnlyRegistry();
if ( regDoc != null )
{
mLocalReg = scanRegistry(regDoc);
}
}
catch (Exception ex)
{
}
}
return (mLocalReg);
}
/**
* Diff the contents of the construction time registry with the copy of the DAS registry.
* The DAS registry is considered the master.
* @return indication of any differences found
*/
public boolean diffRegistry()
throws SyncException
{
Properties props = new Properties();
Registry syncReg;
RegistrySpecImpl rs = null;
try
{
//
// Finish initialization now that we are going to open the registry.
//
mRegistry = (com.sun.jbi.management.registry.Registry)com.sun.jbi.util.EnvironmentAccess.getContext().getRegistry();
mDASRegistryFileName = DAS_RELATIVE_PATH + File.separator + mRegistry.getProperty(Registry.REGISTRY_FILE_PROPERTY);
mSyncRegistryFileName = mRegistry.getProperty(Registry.REGISTRY_SYNC_FILE_PROPERTY);
mSyncFolder = com.sun.jbi.util.EnvironmentAccess.getContext().getJbiInstanceRoot() + "/tmp";
//
// Point at the sync-copy of the master registry.
//
props.put(Registry.REGISTRY_FILE_PROPERTY, mSyncRegistryFileName);
props.put(Registry.REGISTRY_FOLDER_PROPERTY, mSyncFolder);
props.put(Registry.REGISTRY_READONLY_PROPERTY, "true");
//
// Build and open the master.
//
mMasterRegistry = RegistryBuilder.buildRegistry(
rs = new RegistrySpecImpl(RegistryType.XML, props, mRegistry.getRegistrySpec().getManagementContext()));
//
// Compute differences.
//
mDiff = new RegistryDiff(mMasterRegistry, mRegistry, mTarget);
return (mDiff.computeDiff());
}
catch (RegistryException rEx)
{
throw new SyncException(mTranslator.getString(LocalStringKeys.JBI_SYNC_CONFIG_DIFF, rEx));
}
}
/**
* Get the list of new shared libraries in the master.
* @return List of shared library names.
*/
public List<String> getNewSharedLibraries()
{
return (mDiff.getNewSharedLibraries());
}
/**
* Get ComponentInfo about a new SharedLibrary
* @param slName - name of shared library in master
* @return ComponentInfo for the given shared library.
*/
public ComponentInfo getNewSharedLibraryInfo(String slName)
{
return (mDiff.getNewSharedLibraryInfo(slName));
}
/**
* Get the list of old shared libraries in the target.
* @return List of shared library names.
*/
public List<String> getOldSharedLibraries()
{
return (mDiff.getOldSharedLibraries());
}
/**
* Get the list of replaced shared libraries in the target.
* @return List of shared library names.
*/
public List<String> getReplacedSharedLibraries()
{
return (mDiff.getReplacedSharedLibraries());
}
/**
* Get the list of replaced service assemblies in the target.
* @return List of shared library names.
*/
public List<String> getReplacedServiceAssemblies()
{
return (mDiff.getReplacedServiceAssemblies());
}
/**
* Get the list of new components in the master.
* @return List of component names.
*/
public List<String> getNewComponents()
{
return (mDiff.getNewComponents());
}
/**
* Get the list of updated components in the master.
* @return List of component names.
*/
public List<String> getUpdatedComponents()
{
return (mDiff.getUpdatedComponents());
}
/**
* Get the list of replaced components in the master.
* @return List of component names.
*/
public List<String> getReplacedComponents()
{
return (mDiff.getReplacedComponents());
}
/**
* Get ComponentInfo about a new Component
* @param compName - name of component in master
* @return ComponentInfo for the given component
*/
public ComponentInfo getNewComponentInfo(String compName)
{
return (mDiff.getNewComponentInfo(compName));
}
/**
* Get the list of old components in the target.
* @return List of component names.
*/
public List<String> getOldComponents()
{
return (mDiff.getOldComponents());
}
/**
* Get the list of components with lifecycle changes.
* @return List of components names.\
*/
public List<String> getChangedLifeCycleComponents()
{
return (mDiff.getChangedLifeCycleComponents());
}
/**
* Get the list of components affected by other changes. This typically
* means a dependent shared libaray has changed.
* @return List of components names.\
*/
public List<String> getAffectedComponents()
{
return (mDiff.getAffectedComponents());
}
/**
* Get the list of new service assemblies in the master.
* @return List of service assemblies names.
*/
public List<String> getNewServiceAssemblies()
{
return (mDiff.getNewServiceAssemblies());
}
/**
* Get the list of old service assemblies in the target.
* @return List of service assemblies names.
*/
public List<String> getOldServiceAssemblies()
{
return (mDiff.getOldServiceAssemblies());
}
/**
* Compute the state of a new service assembly (exists in master) from the state of the service units.
* @param saName - name of the service assembly
* @return service assembly state
*/
public ServiceAssemblyState getNewServiceAssemblyState(String saName)
{
return (mDiff.getNewServiceAssemblyState(saName));
}
/**
* Get the list of service assemblies affected by other changes. This typically
* means a dependent component has changed.
* @return List of service assembly names.
*/
public List<String> getAffectedServiceAssemblies()
{
return (mDiff.getAffectedServiceAssemblies());
}
/**
* Get the list of service assemblies with lifecycle changes.
* @return List of service assembly names.
*/
public List<String> getChangedLifeCycleServiceAssemblies()
{
return (mDiff.getChangedLifeCycleServiceAssemblies());
}
/**
* Compute the set of components that need to be started so that a deploy service assembly
* operation can execute.
* @return List of components name that need to be started.
*/
public List<String> componentsToStartForDeploy()
{
return (mDiff.componentsToStartForDeploy());
}
/**
* Compute the set of components that need to be started so that a undeploy service assembly
* operation can execute.
* @return List of components name that need to be started.
*/
public List<String> componentsToStartForUndeploy()
{
return (mDiff.componentsToStartForUndeploy());
}
public List<String> getChangedConfigComponents()
{
return (mDiff.getChangedConfigComponents());
}
public Map<String, String> getGlobalConfigChanges(String category)
{
return (mDiff.getGlobalConfigChanges(category));
}
public Map<String, String> getConfigChanges(String category)
{
return (mDiff.getConfigChanges(category));
}
public Map<String, Properties> getComponentPropertyUpdates()
{
return (mDiff.getComponentPropertyUpdates());
}
public Map<String, Variable[]> getAddComponentAppVars()
{
return (mDiff.getAddComponentAppVars());
}
public Map<String, String[]> getRemoveComponentAppVars()
{
return (mDiff.getRemoveComponentAppVars());
}
public Map<String, Map<String, Properties>> getAddComponentConfigs()
{
return (mDiff.getAddComponentConfigs());
}
public Map<String, String> getRemoveComponentConfigs()
{
return (mDiff.getRemoveComponentConfigs());
}
/**
* Download a shared library archive that will be required to perform synchronization actions.
* @param slName - name of shared library to download from the DAS
* @return the string containing the filename with the contents
* @throws SyncException if anything bad happens
*/
public String downloadSharedLibraryArchive(String slName)
throws SyncException
{
Exception e = null;
try
{
Object slId = getSharedLibraryArchiveId(slName);
ComponentInfo ci = mDiff.getNewSharedLibraryInfo(slName);
GenericQuery mQuery = mMasterRegistry.getGenericQuery();
String reposFilename = mQuery.getSharedLibraryFileName(ci.getName());
long timestamp = mQuery.getSharedLibraryTimestamp(ci.getName());
return (downloadFile(slId, reposFilename, timestamp));
}
catch (Exception ex)
{
throw new SyncException(mTranslator.getString(LocalStringKeys.JBI_SYNC_ARCHIVE, ex));
}
}
/**
* Download a component archive that will be required to perform synchronization actions.
* @param compName - name of component to download from the DAS
* @return the string containing the filename with the contents
* @throws SyncException if anything bad happens
*/
public String downloadComponentArchive(String compName)
throws SyncException
{
try
{
Object cId = getComponentArchiveId(compName);
ComponentInfo ci = mDiff.getNewComponentInfo(compName);
GenericQuery mQuery = mMasterRegistry.getGenericQuery();
String reposFilename = mQuery.getComponentFileName(ci.getName());
long timestamp = mQuery.getComponentTimestamp(ci.getName());
return (downloadFile(cId, reposFilename, timestamp));
}
catch (Exception ex)
{
throw new SyncException(mTranslator.getString(LocalStringKeys.JBI_SYNC_ARCHIVE, ex));
}
}
/**
* Download a service assembly archive that will be required to perform synchronization actions.
* @param saName - name of service assembly to download from the DAS
* @return the string containing the filename with the contents
* @throws SyncException if anything bad happens
*/
public String downloadServiceAssemblyArchive(String saName)
throws SyncException
{
try
{
Object saaId = getServiceAssemblyArchiveId(saName);
ServiceAssemblyInfo sai = mDiff.getNewServiceAssemblyInfo(saName);
GenericQuery mQuery = mMasterRegistry.getGenericQuery();
String reposFilename = mQuery.getServiceAssemblyFileName(sai.getName());
long timestamp = mQuery.getServiceAssemblyTimestamp(sai.getName());
return (downloadFile(saaId, reposFilename, timestamp));
}
catch (Exception ex)
{
throw new SyncException(mTranslator.getString(LocalStringKeys.JBI_SYNC_ARCHIVE, ex));
}
}
/**
* Download a file from the DAS into the instances JBI temp directory.
* @param fileId - opaque identifer for remote file on DAS
* @param fileName - used to create a local file
* @param timestamp - that should be applied to the downloaded file.
* @return string containing the name of the file on the local system
* @throws SyncException if anything bad happens
*/
private String downloadFile(Object fileId, String fileName, long timestamp)
throws SyncException
{
byte[] buffer;
File outFile = new File (mInstanceRootPath + "/tmp/" + fileName);
FileOutputStream fis;
Object downId;
try
{
downId = initiateDownload(fileId);
fis = new FileOutputStream(outFile);
while ((buffer = downloadBytes(downId, 8192)).length > 0)
{
fis.write(buffer, 0, buffer.length);
}
terminateDownload(downId);
fis.flush();
fis.close();
if (timestamp != 0)
{
outFile.setLastModified(timestamp);
}
return (outFile.getPath());
}
catch (java.lang.Exception ex)
{
ByteArrayOutputStream b = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(b);
ex.printStackTrace(ps);
ps.flush();
throw new SyncException(mTranslator.getString(LocalStringKeys.JBI_SYNC_FILE_COPY_FAILED,
"jbi-registry.xml", outFile.getName(), b.toString()));
}
}
/**
* Download a file from the DAS into the instances JBI temp directory.
* @return string containing the name of the file on the local system
* @throws SyncException if anything bad happens
*/
private ByteArrayInputStream downloadRegistry()
throws SyncException
{
byte[] buffer;
ByteArrayOutputStream baos;
Object downId;
try
{
downId = initiateRegistryDownload();
baos = new ByteArrayOutputStream();
while ((buffer = downloadBytes(downId, 8192)).length > 0)
{
baos.write(buffer, 0, buffer.length);
}
terminateDownload(downId);
baos.flush();
baos.close();
return (new ByteArrayInputStream(baos.toByteArray()));
}
catch (java.lang.Exception ex)
{
ByteArrayOutputStream b = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(b);
if (ex.getCause() != null)
{
ex.getCause().printStackTrace(ps);
}
ex.printStackTrace(ps);
ps.flush();
throw new SyncException(mTranslator.getString(LocalStringKeys.JBI_SYNC_FILE_COPY_FAILED,
"jbi-registry.xml", "<Memory>", b.toString()));
}
}
/**
* Returns the archive id of a service assembly in the repository.
* @param saName name of the service assembly
* @return archive ID, or null if the service assembly does not exist
* in the repository.
*/
private Object getServiceAssemblyArchiveId(String saName)
throws Exception
{
Object[] params = new Object[]{saName};
String[] sign = new String[]{"java.lang.String"};
return mMBeanServer.invoke(mDASDownloadMBeanName, "getServiceAssemblyArchiveId", params, sign);
}
/**
* Returns the archive id of a component in the repository.
* @param componentName name of the component
* @return archive ID, or null if the component does not exist
* in the repository.
*/
private Object getComponentArchiveId(String componentName)
throws Exception
{
Object[] params = new Object[]{componentName};
String[] sign = new String[]{"java.lang.String"};
return mMBeanServer.invoke(mDASDownloadMBeanName, "getComponentArchiveId", params, sign);
}
/**
* Returns the archive id of a shared library in the repository.
* @param sharedLibrayName name of the shared library
* @return archive ID, or null if the shared library does not exist
* in the repository.
*/
private Object getSharedLibraryArchiveId(String sharedLibraryName)
throws Exception
{
Object[] params = new Object[]{sharedLibraryName};
String[] sign = new String[]{"java.lang.String"};
return mMBeanServer.invoke(mDASDownloadMBeanName, "getSharedLibraryArchiveId", params, sign);
}
/**
* Initiate the download of the specified file.
*/
private Object initiateDownload(Object archiveId)
throws Exception
{
Object[] params = new Object[]{archiveId};
String[] sign = new String[]{"java.lang.Object"};
return mMBeanServer.invoke(mDASDownloadMBeanName, "initiateDownload", params, sign);
}
/**
* Initiate the download of the specified file.
*/
private Object initiateRegistryDownload()
throws Exception
{
return mMBeanServer.invoke(mDASDownloadMBeanName, "initiateRegistryDownload", new Object[0], new String[0]);
}
/**
* Download Bytes.
*/
private byte[] downloadBytes(Object downId, int count)
throws Exception
{
Object[] params = new Object[]{downId, Integer.valueOf(count)};
String[] sign = new String[]{"java.lang.Object", "int"};
return (byte[])mMBeanServer.invoke(mDASDownloadMBeanName, "downloadBytes", params, sign);
}
/**
* Terminate the Upload.
*/
private void terminateDownload(Object downId)
throws Exception
{
Object[] params = new Object[]{downId};
String[] sign = new String[]{"java.lang.Object"};
mMBeanServer.invoke(mDASDownloadMBeanName, "terminateDownload", params, sign);
}
/**
* This method performs a quick scan of a registry and extracts state needed to
* decide if an instance requires synchronization.
* @param filename - contains the registry to scan
* @return HashMap
* @throws Exception on any problem
*/
private HashMap<String,HashMap> scanRegistry(InputStream is)
throws Exception
{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(is);
return scanRegistry(doc);
}
/**
* This method performs a quick scan of a registry and extracts state needed to
* decide if an instance requires synchronization.
* @param doc - the registry document object
* @return HashMap
* @throws Exception on any problem
*/
private HashMap<String,HashMap> scanRegistry(Document doc)
throws Exception
{
String targetName = mPlatform.getTargetName();
HashMap<String, HashMap> result = new HashMap();
NodeList instances;
Element target = null;
if (mPlatform.isStandaloneServer(targetName))
{
instances = doc.getDocumentElement().getElementsByTagName("server");
}
else
{
instances = doc.getDocumentElement().getElementsByTagName("cluster");
}
if (instances != null)
{
for (int i = 0; i < instances.getLength(); i++)
{
Element instance = (Element)instances.item(i);
if (instance.getAttribute("name-ref").equalsIgnoreCase(targetName))
{
target = instance;
break;
}
}
if (target != null)
{
result.put(COMP_KEY, makeRefMap(makeElementMap(
doc.getDocumentElement(), JBI_SCHEMA_COMPONENT),
target, JBI_SCHEMA_COMPONENT_REF, JBI_SCHEMA_NAME_REF));
result.put(SL_KEY, makeRefMap(makeElementMap(
doc.getDocumentElement(), JBI_SCHEMA_SHARED_LIBRARY),
target, JBI_SCHEMA_SHARED_LIBRARY_REF, JBI_SCHEMA_NAME_REF));
result.put(SA_KEY, makeSURefMap(makeElementMap(
doc.getDocumentElement(), JBI_SCHEMA_SERVICE_ASSEMBLY), target));
result.put(DOMAIN_KEY, makeConfigMap(doc.getDocumentElement(), "domain-config"));
result.put(INSTANCE_KEY, makeConfigMap(doc.getDocumentElement(), targetName + "-config")); }
makeConfigurationMap(result, target);
}
return (result);
}
/**
* This method extracts config information from the registry.
* @param e - DOM Element to start tag search
* @param targetName - instance to process
* @return HashMap keyed by name containing the EntityInfo.
*/
private static HashMap<String, HashMap> makeConfigMap(Element e, String targetName)
{
NodeList instances;
Element target = null;
HashMap configMap = new HashMap();
instances = e.getElementsByTagName(JBI_SCHEMA_CONFIG);
if (instances != null)
{
for (int i = 0; i < instances.getLength(); i++)
{
Element instance = (Element)instances.item(i);
if (instance.getAttribute(JBI_SCHEMA_NAME).equalsIgnoreCase(targetName))
{
target = instance;
break;
}
}
}
if (target != null)
{
instances = target.getElementsByTagName(JBI_SCHEMA_CONFIG_TYPE);
if (instances != null)
{
for (int i = 0; i < instances.getLength(); i++)
{
Element instance = (Element)instances.item(i);
String category = instance.getAttribute(JBI_SCHEMA_CATEGORY);
if (category.equals("Logger"))
{
continue;
}
NodeList properties = instance.getElementsByTagName(JBI_SCHEMA_PROPERTY);
HashMap<String, String> map = null;
if (properties != null)
{
map = new HashMap();
for (int j = 0; j < properties.getLength(); j++)
{
String name;
String value;
Element property;
property = (Element)properties.item(j);
Text prop1 = (Text)property.getFirstChild();
Text prop2 = (Text)property.getLastChild();;
if (prop1.getWholeText().equals(JBI_SCHEMA_NAME))
{
name = prop1.getWholeText();
value = prop2.getWholeText();
}
else
{
name = prop2.getWholeText();
value = prop1.getWholeText();
}
map.put(name, value);
}
configMap.put(category, map);
}
}
}
}
return (configMap);
}
/**
* This method extracts NAME and TIMESTAMP attributes from the requested tag.
* @param e - DOM Element to start tag search
* @param tag - to search for
* @return HashMap keyed by name containing the EntityInfo.
*/
private static HashMap<String, EntityInfo> makeElementMap(Element e, String tag)
{
HashMap<String, EntityInfo> map = new HashMap();
NodeList tags = e.getElementsByTagName(tag);
for (int i = 0; i < tags.getLength(); i++)
{
Element instance = (Element)tags.item(i);
EntityInfo ei = new EntityInfo();
ei.mName = instance.getAttribute(JBI_SCHEMA_NAME);
ei.mTimestamp = instance.getAttribute(JBI_SCHEMA_TIMESTAMP);
ei.mUpdateNumber = instance.getAttribute(JBI_SCHEMA_UPDATENUMBER);
if (ei.mUpdateNumber == null)
{
ei.mUpdateNumber = "";
}
map.put(ei.mName, ei);
}
return (map);
}
/**
* This method merges the generic entity and specific entity information into a single result.
* Typically, this means extracting the STATE information and updating the cooresponding EntityInfo.
* @param emap - HashMap containing generic EntityIno
* @param e - DOM Element to used as the search anchor
* @param tag - Tag of the Entity to find in e
* @param nametag - Tag of Attribute in found Entity to use as a lookup for EntityInfo.
* @return HashMap keyed by name containing the EntityInfo.
*/
private static HashMap<String, EntityInfo> makeRefMap(HashMap<String,EntityInfo> emap, Element e, String tag, String nametag)
{
HashMap<String, EntityInfo> map = new HashMap();
NodeList tags = e.getElementsByTagName(tag);
for (int i = 0; i < tags.getLength(); i++)
{
Element instance = (Element)tags.item(i);
String nameref = instance.getAttribute(nametag);
EntityInfo ei = emap.get(nameref);
if (nameref != null)
{
ei.mState = instance.getAttribute(JBI_SCHEMA_STATE);
ei.mUpdateNumber = instance.getAttribute(JBI_SCHEMA_UPDATENUMBER);
if (ei.mUpdateNumber == null)
{
ei.mUpdateNumber = "";
}
map.put(nameref, ei);
}
}
return (map);
}
/**
* This method specificly handles ServiceAssembly/ServiceUnit result building (this is a 1<->N
* relationship.) The result size corresponds to the ServiceUnit count.
* @param emap - HashMap containing generic EntityInfo
* @param e - DOM Element to used as the search anchor
* @return HashMap keyed by name containing the EntityInfo.
*/
private static HashMap<String, EntityInfo> makeSURefMap(HashMap<String,EntityInfo> emap, Element e)
{
HashMap<String, EntityInfo> map = new HashMap();
NodeList tags = e.getElementsByTagName(JBI_SCHEMA_SERVICE_UNIT);
for (int i = 0; i < tags.getLength(); i++)
{
Element instance = (Element)tags.item(i);
String sanameref = instance.getAttribute(JBI_SCHEMA_SERVICE_ASSEMBLY_REF);
if (sanameref != null)
{
EntityInfo ei = emap.get(sanameref);
EntityInfo nei = new EntityInfo();
nei.mName = instance.getAttribute(JBI_SCHEMA_NAME);
nei.mState = instance.getAttribute(JBI_SCHEMA_STATE);
nei.mUpdateNumber = instance.getAttribute(JBI_SCHEMA_UPDATENUMBER);
if (nei.mUpdateNumber == null)
{
nei.mUpdateNumber = "";
}
nei.mTimestamp = ei.mTimestamp;
map.put(nei.mName, nei);
}
}
return (map);
}
private static void makeConfigurationMap(HashMap<String, HashMap> result, Element e)
{
NodeList components = e.getElementsByTagName(JBI_SCHEMA_COMPONENT_REF);
if (components != null)
{
for (int i = 0; i < components.getLength(); i++)
{
Element ref = (Element)components.item(i);
String nameRef = ref.getAttribute(JBI_SCHEMA_NAME_REF);
NodeList configs = ref.getElementsByTagName(JBI_SCHEMA_COMPONENT_CONFIG);
if (configs != null)
{
Element config = (Element)configs.item(0);
if (config != null)
{
result.put(STATIC_CONF_KEY, getProperties(config));
result.put(APPVAR_CONF_KEY, getApplicationVariables(config));
result.put(APPCON_CONF_KEY, getApplicationConfiguration(config));
}
}
}
}
}
private static HashMap<String, AppVarInfo> getApplicationVariables(Element e)
{
NodeList apps = e.getElementsByTagName(JBI_SCHEMA_APPLICATION_VARIABLE);
HashMap<String, AppVarInfo> appCon = new HashMap();
if (apps != null)
{
for (int i = 0; i < apps.getLength(); i++)
{
Element app = (Element)apps.item(i);
Node nameNode = app.getFirstChild();
Node valueNode = nameNode.getNextSibling();
Node typeNode = valueNode.getNextSibling();
AppVarInfo avi = new AppVarInfo();
avi.mType = typeNode.getTextContent();
avi.mValue = valueNode.getTextContent();
appCon.put(nameNode.getTextContent(), avi);
}
}
return (appCon);
}
private static HashMap<String, HashMap> getApplicationConfiguration(Element e)
{
NodeList apps = e.getElementsByTagName(JBI_SCHEMA_APPLICATION_CONFIGURATION);
HashMap<String, HashMap> appCon = new HashMap();
if (apps != null)
{
for (int i = 0; i < apps.getLength(); i++)
{
Element app = (Element)apps.item(i);
String appconName = app.getAttribute(JBI_SCHEMA_NAME);
appCon.put(appconName, getProperties(app));
}
}
return (appCon);
}
private static HashMap<String, String> getProperties(Element e)
{
NodeList props = e.getElementsByTagName(JBI_SCHEMA_PROPERTY);
HashMap<String,String> result = new HashMap();
if (props != null)
{
for (int i = 0; i < props.getLength(); i++)
{
Element prop = (Element)props.item(i);
Node nameNode = prop.getFirstChild();
Node valueNode = nameNode.getNextSibling();
result.put(nameNode.getTextContent(), valueNode.getTextContent());
}
}
return (result);
}
/**
* This method determines if all components are in SHUTDOWN state.
* @param map - HashMap containing the local values
* @return int answering question is they are different
**/
private boolean allShutdown(HashMap map)
{
boolean result = true;
if (map != null)
{
HashMap<String,EntityInfo> local = (HashMap)map.get(COMP_KEY);
if (local != null)
{
for (Map.Entry<String,EntityInfo> e : local.entrySet())
{
EntityInfo ie = e.getValue();
if (ie.mState.equals(ComponentState.getLifeCycleState(ComponentState.SHUTDOWN)))
{
continue;
}
result = false;
break;
}
}
}
return (result);
}
/**
* This method computes if a material difference exists between two registry contents.
* @param syncMap - HashMap containing the reference
* @param localMap - HashMap containing the local value
* @return boolean answering question is they are different
**/
private int regMapsDiff(HashMap syncMap, HashMap localMap)
{
int result = localMap == null ? SYNC_REQUIRED: 0;
if (result != SYNC_REQUIRED)
{
result = diff(syncMap, localMap, COMP_KEY);
}
if (result != SYNC_REQUIRED)
{
result = diff(syncMap, localMap, SL_KEY);
}
if (result != SYNC_REQUIRED)
{
result = diff(syncMap, localMap, SA_KEY);
}
if (result != SYNC_REQUIRED)
{
result = diffConfig(syncMap, localMap, DOMAIN_KEY);
}
if (result != SYNC_REQUIRED)
{
result = diffConfig(syncMap, localMap, INSTANCE_KEY);
}
if (result != SYNC_REQUIRED)
{
result = diffStaticProps(syncMap, localMap, STATIC_CONF_KEY);
}
if (result != SYNC_REQUIRED)
{
result = diffAppVars(syncMap, localMap, APPVAR_CONF_KEY);
}
if (result != SYNC_REQUIRED)
{
result = diffAppConf(syncMap, localMap, APPCON_CONF_KEY);
}
return (result);
}
private int diff(HashMap<String, HashMap> syncMap, HashMap<String, HashMap> localMap, String key)
{
HashMap<String,EntityInfo> sync = (HashMap)syncMap.get(key);
HashMap<String,EntityInfo> local = (HashMap)localMap.get(key);
int result = SYNC_REQUIRED;
if (sync != null && local != null && sync.size() == local.size())
{
result = 0;
for (Map.Entry<String,EntityInfo> e : sync.entrySet())
{
EntityInfo sie = e.getValue();
EntityInfo lie = local.get(sie.mName);
if (lie != null &&
sie.mTimestamp.equals(lie.mTimestamp) &&
sie.mState.equals(lie.mState) &&
sie.mUpdateNumber.equals(lie.mUpdateNumber))
{
continue;
}
result = SYNC_REQUIRED;
break;
}
}
return (result);
}
private int diffConfig(HashMap<String, HashMap> syncMap, HashMap<String, HashMap> localMap, String key)
{
HashMap<String,HashMap> sync = (HashMap)syncMap.get(key);
HashMap<String,HashMap> local = (HashMap)localMap.get(key);
int result = SYNC_REQUIRED;
if (sync != null && local != null && sync.size() == local.size())
{
result = 0;
for (Map.Entry<String,HashMap> e : sync.entrySet())
{
String category = e.getKey();
HashMap<String,String> cats = e.getValue();
HashMap<String,String> locals = local.get(category);
if (locals != null &&
cats.size() == locals.size())
{
for (String name : cats.keySet())
{
String value = locals.get(name);
if (value != null)
{
if (cats.get(name).equals(value))
{
continue;
}
}
result = SYNC_REQUIRED;
break;
}
if (result == 0)
{
continue;
}
}
result = SYNC_REQUIRED;
break;
}
}
return (result);
}
private int diffStaticProps(HashMap<String, HashMap> syncMap, HashMap<String, HashMap> localMap, String key)
{
HashMap<String,String> sync = (HashMap)syncMap.get(key);
HashMap<String,String> local = (HashMap)localMap.get(key);
int result = SYNC_REQUIRED;
return (diffProps(sync, local));
}
private int diffAppVars(HashMap<String, HashMap> syncMap, HashMap<String, HashMap> localMap, String key)
{
HashMap<String,AppVarInfo> sync = (HashMap)syncMap.get(key);
HashMap<String,AppVarInfo> local = (HashMap)localMap.get(key);
int result = 0;
if (sync != null || local != null)
{
result = SYNC_REQUIRED;
if (sync != null && local != null && sync.size() == local.size())
{
result = 0;
for (Map.Entry<String,AppVarInfo> e : sync.entrySet())
{
String confKey = e.getKey();
AppVarInfo value = e.getValue();
AppVarInfo localValue = local.get(confKey);
if (localValue != null &&
value.mType.equals(localValue.mType) &&
value.mValue.equals(localValue.mValue))
{
continue;
}
result = SYNC_REQUIRED;
break;
}
}
}
return (result);
}
private int diffAppConf(HashMap<String, HashMap> syncMap, HashMap<String, HashMap> localMap, String key)
{
HashMap<String,HashMap> sync = (HashMap)syncMap.get(key);
HashMap<String,HashMap> local = (HashMap)localMap.get(key);
int result = 0;
if (sync != null || local != null)
{
result = SYNC_REQUIRED;
if (sync != null && local != null && sync.size() == local.size())
{
result = 0;
for (Map.Entry<String,HashMap> e : sync.entrySet())
{
String config = e.getKey();
HashMap<String,String> value = e.getValue();
HashMap<String,String> localValue = local.get(config);
if (diffProps(value, localValue) == 0)
{
continue;
}
result = SYNC_REQUIRED;
break;
}
}
}
return (result);
}
private int diffProps(HashMap<String,String> sync, HashMap<String,String> local)
{
int result = 0;
if (sync != null || local != null)
{
result = SYNC_REQUIRED;
if (sync != null && local != null && sync.size() == local.size())
{
result = 0;
for (Map.Entry<String,String> e : sync.entrySet())
{
String confKey = e.getKey();
String value = e.getValue();
String localValue = local.get(confKey);
if (localValue != null && value.equals(localValue))
{
continue;
}
result = SYNC_REQUIRED;
break;
}
}
}
return (result);
}
/**
* Temporary mostly for debugging purposes.
*/
public void displayActions()
{
mLogger.info(mDiff.toString());
}
}
class EntityInfo
{
String mName;
String mTimestamp;
String mUpdateNumber;
String mState;
}
class AppVarInfo
{
String mValue;
String mType;
}
|