com.sun.enterprise.registration.impl.RepositoryManager Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.registration.impl;
import com.sun.enterprise.registration.RegistrationService.RegistrationStatus;
import com.sun.enterprise.registration.RegistrationService.RegistrationReminder;
import com.sun.enterprise.registration.RegistrationException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.Logger;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.ArrayList;
import java.util.List;
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
/**
*
* @author msiraj
* @author tjquinn
*/
/** Manages a local repository for service tags and registration status.
*
* The client code specifies (in the constructor) the file path or the File
* which is to hold the persisted registration repository. Note that any public
* method that modifies any part of the DOM for the repository also
* flushes the repository to the file before returning.
*
* If the specified file exists, the manager loads its contents as the initial
* value of the document. If the file does not exist, the manager creates a
* new in-memory document containing the top-level registry element and the
* default registrationstatus element but does NOT write out this initial data.
* Writes to the file occur only in response to the client code invoking one of
* the methods that modifies the DOM.
*/
public class RepositoryManager {
private Logger logger = Logger.getLogger(getClass().getPackage().getName());
/**
* Creates a new manager which persists the registration data in the specified File.
* @throws RegistrationException for any errors creating the XML parser or
* transformer used for reading and writing the registration data or during
* the initial load of the repository from the local file
*/
public RepositoryManager(File registrationFile) throws RegistrationException {
this.registrationFile = registrationFile;
try {
logger.fine("RepositoryManager created for file " + registrationFile.getCanonicalPath());
documentBuilder = documentBuilderFactory.newDocumentBuilder();
transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount","4");
loadOrCreateDocument();
} catch (Exception e) {
throw new RegistrationException(e);
}
}
/**
* Returns a list of all service tag objects represented in the repository.
* @return List
* the in-memory cache (if it is not already there)
*/
public List getServiceTags() {
NodeList nodes = document.getElementsByTagName(ServiceTag.SERVICE_TAG);
List serviceTags = new ArrayList();
/* nodes is guaranteed to be non-null */
for(int i = 0 ; i < nodes.getLength();i++) {
Element elem = (Element)nodes.item(i);
serviceTags.add(new ServiceTag(elem));
}
return serviceTags;
}
/**
* Returns the current registration status value.
* Returns RegistrationService.REGISTERED if any one service tag is registered.
* @return RegistrationService.RegistrationStatus enum for the current registration status
*/
public RegistrationStatus getRegistrationStatus() {
NodeList nodes = document.getElementsByTagName(ServiceTag.SERVICE_TAG);
for(int i = 0 ; i < nodes.getLength();i++) {
Element elem = (Element)nodes.item(i);
RegistrationStatus rs =
RegistrationStatus.valueOf(getSubElementValue(elem, ServiceTag.REGISTRATION_STATUS));
if (rs.equals(RegistrationStatus.REGISTERED))
return rs;
}
return RegistrationStatus.NOT_REGISTERED;
}
/**
* Sets the registration status value for all service tags and persists the change
* to the on-disk repository.
* @param status the new RegistrationStatus value
* @throws RegistrationException for errors writing the registration data
* to the local repository
*/
public void setRegistrationStatus(RegistrationStatus status) throws RegistrationException {
NodeList nodes = document.getElementsByTagName(ServiceTag.SERVICE_TAG);
for(int i = 0 ; i < nodes.getLength();i++) {
Element elem = (Element)nodes.item(i);
setSubElementValue(elem, ServiceTag.REGISTRATION_STATUS, status.toString());
}
writeToFile();
}
/**
* Returns the current registration status value.
* @return RegistrationService.RegistrationReminder enum for the current registration status
*/
public RegistrationReminder getRegistrationReminder() {
Element regElement = findRegistrationReminderElement();
return RegistrationReminder.valueOf(regElement.getTextContent());
}
/**
* Sets the registration status value and persists the change to the on-disk
* repository.
* @param reminder the new RegistrationReminder value
* @throws RegistrationException for errors writing the registration data
* to the local repository
*/
public void setRegistrationReminder(RegistrationReminder reminder) throws RegistrationException {
findRegistrationReminderElement().setTextContent(reminder.toString());
writeToFile();
}
/**
* Adds an element for the specified ServiceTag object (and writes the revised
* DOM to the file).
* @param serviceTag the ServiceTag for which to add an XML element
* @throws RegistrationException for errors writing the registration data
* to the local repository
*/
public void add(ServiceTag serviceTag) throws RegistrationException {
Element st = findServiceTag(serviceTag);
if (st != null) {
throw new RegistrationException(StringManager.getString("rpmgr.svrTagExists"));
//throw new RegistrationException("rpmgr.svrTagExists");
}
/*
* Create a new Element in the active document using the specified
* service tag information.
*/
st = serviceTag.getElement(document);
Element registrationReminderElement = findRegistrationReminderElement();
/*
* Insert the new service tag just before the registration status element, if it
* is found. Otherwise insert it under registryElement
*/
if (registrationReminderElement != null) {
registryElement.insertBefore(st, registrationReminderElement);
}
else {
registryElement.appendChild(st);
}
writeToFile();
}
/**
* Removes the XML element corresponding to the specified service tag (and
* persists the change to the file).
* @param serviceTag the ServiceTag for which the XML element should be removed
* @throws RegistrationException for errors writing the registration data
* to the local repository
*/
public void remove(ServiceTag serviceTag) throws RegistrationException {
Element st = findServiceTag(serviceTag);
if (st == null) {
throw new RegistrationException(StringManager.getString("rpmgr.noSuchSrvTag"));
//throw new RegistrationException("rpmgr.noSuchSrvTag");
}
registryElement.removeChild(st);
writeToFile();
}
/**
* Sets the status for the specified service tag in the repository (and
* persists the change to the file).
* @param serviceTag the service tag of interest
* @param the status to be assigned
* @throws RegistrationException for errors writing the registration data
* to the local repository
*/
public void setRegistrationStatus(ServiceTag serviceTag, ServiceTag.RegistrationStatus status) throws RegistrationException {
Element st = findServiceTag(serviceTag);
if (st == null) {
throw new RegistrationException(StringManager.getString("rpmgr.noSuchSrvTag"));
}
setSubElementValue(st, ServiceTag.REGISTRATION_STATUS, status.toString());
writeToFile();
}
public ServiceTag.RegistrationStatus getRegistrationStatus(ServiceTag serviceTag) throws RegistrationException {
Element st = findServiceTag(serviceTag);
if (st == null) {
throw new RegistrationException(StringManager.getString("rpmgr.noSuchSrvTag"));
}
return ServiceTag.RegistrationStatus.valueOf(getSubElementValue(st, ServiceTag.REGISTRATION_STATUS));
}
public void setStatus(ServiceTag serviceTag, ServiceTag.Status status) throws RegistrationException {
Element st = findServiceTag(serviceTag);
if (st == null) {
throw new RegistrationException(StringManager.getString("rpmgr.noSuchSrvTag"));
}
setSubElementValue(st, ServiceTag.STATUS, status.toString());
writeToFile();
}
public ServiceTag.Status getStatus(ServiceTag serviceTag) throws RegistrationException {
Element st = findServiceTag(serviceTag);
if (st == null) {
throw new RegistrationException(StringManager.getString("rpmgr.noSuchSrvTag"));
}
return ServiceTag.Status.valueOf(getSubElementValue(st, ServiceTag.STATUS));
}
public String getInstanceURN(String productURN) throws RegistrationException {
NodeList nodes = document.getElementsByTagName(ServiceTag.SERVICE_TAG);
for(int i = 0 ; i < nodes.getLength();i++) {
Element elem = (Element)nodes.item(i);
String productURN1 = getSubElementValue(elem, ServiceTag.PRODUCT_URN);
if (productURN.equals(productURN1))
return getSubElementValue(elem, ServiceTag.INSTANCE_URN);
}
return null;
}
public boolean setInstanceURN(String productURN, String instanceURN)
throws RegistrationException {
NodeList nodes = document.getElementsByTagName(ServiceTag.SERVICE_TAG);
for(int i = 0 ; i < nodes.getLength();i++) {
Element elem = (Element)nodes.item(i);
String productURN1 = getSubElementValue(elem, ServiceTag.PRODUCT_URN);
if (productURN.equals(productURN1)) {
setSubElementValue(elem, ServiceTag.INSTANCE_URN, instanceURN);
writeToFile();
return true;
}
}
//throw new RegistrationException("No such productURN : " + productURN);
return false;
}
/**
* Goes through all service tags in the repository, and updates runtime
* values if necessary.
* @throws RegistrationException in case of errors writing the output
*/
public void updateRuntimeValues() throws RegistrationException {
NodeList nodes = document.getElementsByTagName(ServiceTag.SERVICE_TAG);
/* nodes is guaranteed to be non-null */
for(int i = 0 ; i < nodes.getLength();i++) {
Element elem = (Element)nodes.item(i);
/* generate value for instanceURN if necessary */
String instanceURN = getSubElementValue(elem, ServiceTag.INSTANCE_URN);
if (instanceURN == null || instanceURN.length() == 0) {
instanceURN = ServiceTag.getNewInstanceURN();
setSubElementValue(elem, ServiceTag.INSTANCE_URN, instanceURN, true);
}
/* generate value for platformArchif necessary */
String platformArch = getSubElementValue(elem, ServiceTag.PLATFORM_ARCH);
if (platformArch == null || platformArch.length() == 0) {
platformArch = System.getProperty("os.arch");
setSubElementValue(elem, ServiceTag.PLATFORM_ARCH, platformArch, true);
}
/* generate value for product_defined_inst_id if necessary */
String product_defined_inst_id = getSubElementValue(elem, ServiceTag.PRODUCT_DEFINED_INST_ID);
if (product_defined_inst_id == null || product_defined_inst_id.length() == 0) {
product_defined_inst_id = ServiceTag.getDefaultProductDefinedInstID();
setSubElementValue(elem, ServiceTag.PRODUCT_DEFINED_INST_ID, product_defined_inst_id, true);
}
}
writeToFile();
}
/**
* Writes the contents of the specified Node to the OutputStream provided.
*
* Typically used for testing and debugging. Not intended as part of the
* normally-used public interface.
* @param node the root of the subtree to write out
* @param stream the OutputStream to which to write the XML
* @throws RegistrationException in case of errors writing the output
*/
void write(Node node, OutputStream stream) throws RegistrationException {
try {
transformer.transform(new DOMSource(node), new StreamResult(stream));
} catch (Exception e) {
throw new RegistrationException(e);
}
}
/**
* Writes the cached document to the provided output stream
*
* Typically used for testing and debugging. Not intended as part of the
* normally-used public interface.
* @param stream the OutputStream to which to write the document
* @throws RegistrationException in case of errors writing the output
*/
void write(OutputStream stream) throws RegistrationException {
write(document, stream);
}
/**
* Locates the registration status element from the document.
*
* If absent, adds the element to the end of the document and initializes it to
* the default value.
* @return Element for the registration status
*/
private Element findRegistrationReminderElement() {
Element result = null;
NodeList nodes = document.getElementsByTagName(REGISTRATION_REMINDER_TAG);
if (nodes.getLength() > 0) {
/*
* There should be at most one, but take the first if
* there is at least one.
*/
result = (Element)nodes.item(0);
}
return result;
}
/**
* Locates the servicetag element corresponding to the specified ServiceTag
* object.
* @param serviceTag the ServiceTag for which to find the corresponding element
* @return the Element for that service tag; null if not found
*/
private Element findServiceTag(ServiceTag serviceTag) {
Element result = null;
NodeList nodes = document.getElementsByTagName(ServiceTag.SERVICE_TAG);
for (int i = 0; i < nodes.getLength(); i++) {
if (isSameServiceTag(serviceTag, nodes.item(i))) {
result = (Element) nodes.item(i);
break;
}
}
return result;
}
/**
* Indicates whether the specified ServiceTag object and the specified Node
* represent the same service tag, based on the unique identifying information.
* @param serviceTag the ServiceTag of interest
* @param candidateNode the node that may represent the ServiceTag
* @return boolean if the node represents the specified service tag
*/
private boolean isSameServiceTag(ServiceTag serviceTag, Node candidateNode) {
boolean result = false;
if (candidateNode instanceof Element) {
Element candidateElement = (Element) candidateNode;
String productURN = getSubElementValue(candidateElement, ServiceTag.PRODUCT_URN);
String instanceURN = getSubElementValue(candidateElement, ServiceTag.INSTANCE_URN);
if (productURN != null && instanceURN != null ) {
result = productURN.equals(serviceTag.getSvcTag().getProductURN())
&& instanceURN.equals(serviceTag.getSvcTag().getInstanceURN());
}
}
return result;
}
private String getSubElementValue(Element rootElement, String subElementName ) {
NodeList nodes = rootElement.getElementsByTagName(subElementName);
if (nodes.getLength() > 0) {
return ((Element)nodes.item(0)).getTextContent();
}
return null;
}
private void setSubElementValue(Element rootElement, String subElementName, String value)
throws RegistrationException {
setSubElementValue(rootElement, subElementName, value, false);
/*
NodeList nodes = rootElement.getElementsByTagName(subElementName);
if (nodes.getLength() > 0) {
Element subElement = ((Element)nodes.item(0));
subElement.setTextContent(value);
}
else {
throw new RegistrationException(StringManager.getString("rpmgr.noSuchElement"));
}
*/
}
private void setSubElementValue(Element rootElement, String subElementName, String value, boolean force)
throws RegistrationException {
NodeList nodes = rootElement.getElementsByTagName(subElementName);
if (nodes.getLength() > 0) {
Element subElement = ((Element)nodes.item(0));
subElement.setTextContent(value);
}
else {
if (force) {
Element element = document.createElement(subElementName);
element.setTextContent(value);
rootElement.appendChild(element);
}
else {
throw new RegistrationException(StringManager.getString("rpmgr.noSuchElement"));
}
}
}
/**
* Initializes the cached Document for the repository.
*
* If the specified file exists, reads the document from that file. If the
* file does not exist, creates a new document and populates it with the
* top-level registry element and the default registrationstatus element.
* @throws RegistrationException for errors reading the registration into
* the in-memory cache
*/
private synchronized void loadOrCreateDocument() throws RegistrationException {
if (document == null) {
if (registrationFile.exists()) {
try {
document = documentBuilder.parse(registrationFile);
registryElement = findRegistryElement();
} catch (Exception e) {
throw new RegistrationException(e);
}
}
else {
document = documentBuilder.newDocument();
registryElement = document.createElement(REGISTRY_TAG);
document.appendChild(registryElement);
Element registrationStatusElement = document.createElement(REGISTRATION_REMINDER_TAG);
registrationStatusElement.setTextContent(REGISTRATION_REMINDER_DEFAULT_VALUE.toString());
registryElement.appendChild(registrationStatusElement);
}
}
}
/**
* Writes the cached document to the on-disk file.
* @throws RegistrationException for errors writing the cache into the file
*/
private void writeToFile() throws RegistrationException {
OutputStream os = null;
try {
os = new FileOutputStream(registrationFile);
write(os);
} catch (Exception e) {
throw new RegistrationException(e);
} finally {
if (os != null) {
try {
os.close();
} catch (IOException ex) {
throw new RegistrationException(StringManager.getString("rpmgr.errClosingRepos"), ex);
}
}
}
}
/**
* Locates the top-level element, the registry element.
* @return the top-level registry element
*/
private Element findRegistryElement() {
Element result = null;
NodeList nodes = document.getElementsByTagName(REGISTRY_TAG);
if (nodes.getLength() > 0) {
result = (Element) nodes.item(0);
}
return result;
}
/** element name for the registrationstatus element */
private static final String REGISTRATION_REMINDER_TAG = "registration_reminder";
/** element name for the top-level registry element */
private static final String REGISTRY_TAG = "registry";
/** default value for the registration status element */
private static final RegistrationReminder REGISTRATION_REMINDER_DEFAULT_VALUE =
RegistrationReminder.ASK_FOR_REGISTRATION;
/*
* Doc builder factory, doc builder, transformer factory, and transformer
* are all reusable so get them once.
*/
private final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
private final DocumentBuilder documentBuilder;
private final TransformerFactory transformerFactory = TransformerFactory.newInstance();
private final Transformer transformer;
/** the file to write the registration data to and read it from */
private File registrationFile = null;
/** the cached in-memory data */
private Document document = null;
/** the cached top-level registry element */
private Element registryElement = null;
}