VirtualMetaPropertiesXMLConverter.java :  » Portal » mypersonalizer » es » udc » mypersonalizer » kernel » model » xmlconverters » Java Open Source

Java Open Source » Portal » mypersonalizer 
mypersonalizer » es » udc » mypersonalizer » kernel » model » xmlconverters » VirtualMetaPropertiesXMLConverter.java
/*
 * $Header: /export/home/cvsroot/MyPersonalizerRepository/MyPersonalizer/Subsystems/Kernel/Sources/es/udc/mypersonalizer/kernel/model/xmlconverters/VirtualMetaPropertiesXMLConverter.java,v 1.1.1.1 2004/03/25 12:08:37 fbellas Exp $
 * $Revision: 1.1.1.1 $
 * $Date: 2004/03/25 12:08:37 $
 *
 * =============================================================================
 *
 * Copyright (c) 2003, The MyPersonalizer Development Group
 * (http://www.tic.udc.es/~fbellas/mypersonalizer/index.html) at 
 * University Of A Corua
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 *  - Neither the name of the University Of A Corua nor the names of its 
 *    contributors may be used to endorse or promote products derived from 
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */
package es.udc.mypersonalizer.kernel.model.xmlconverters;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;

import es.udc.mypersonalizer.kernel.model.annotators.Annotations;
import es.udc.mypersonalizer.kernel.model.annotators.sql.SQLPersistenceTypeAnnotationHelper;
import es.udc.mypersonalizer.kernel.model.metainfo.MetaProperty;
import es.udc.mypersonalizer.kernel.model.metainfo.MetaService;
import es.udc.mypersonalizer.kernel.model.metainfo.MetaServiceRegistrySingleton;
import es.udc.mypersonalizer.kernel.model.query.virtualmetainfo.
    LinkMetaPropertyAnnotationHelper;
import es.udc.mypersonalizer.kernel.model.query.virtualmetainfo.
    VirtualMetaPropertyAnnotationHelper;
import es.udc.mypersonalizer.kernel.util.exceptions.InternalErrorException;
import es.udc.mypersonalizer.kernel.util.general.Cloner;
import es.udc.mypersonalizer.kernel.util.xml.DefaultErrorHandler;
import es.udc.mypersonalizer.kernel.util.xml.LocalEntityResolver;
import es.udc.mypersonalizer.kernel.util.xml.WarningsHandler;

/**
 * Utility class that converts an XML file defining the virtual metaproperties
 * in a map of virtual metaproperties indexed by <i>unique name</i>.
 * <p>
 * A <i>unique name</i> is similar to a <code>MetaProperty</code> scoped name,
 * but replacing the root metaproperty name with the service identifier.
 * <p>
 * Some additional checks are made to avoid illegal declarations:
 * <ul>
 * <li>Virtual metaproperties can't have the same unique name as any other 
 * metaproperty (real or virtual).</li>
 * <li>Virtual metaproperties links must reference exisiting metaservices and
 * metaproperties.</li>
 * </ul>
 *  
 * @author Abel Muinho
 * @since 1.0
 */
public class VirtualMetaPropertiesXMLConverter {
    /** DTD's <code>publicId</code>. */
    public static String DTD_PUBLIC_ID = 
        "-//MyPersonalizer//"
        + "DTD MyPersonalizer Virtual Metaproperties Configuration 1.0//EN";
    
    /** File name to resolve DTD's <code>publicId</code>. */
    public static String DTD_LOCAL_FILE_NAME = 
        "myper-virtual-metaproperties-config_1_0.dtd";
    
    /** Name of the node containing the definition of virtual metaproperties.
     * Value: <code>virtual-metaproperties</code>.
     */
    private static final String VIRTUAL_PROPERTIES_NODE = 
        "virtual-metaproperties";
        
    /** Name of the node containing the definition of a virtual property
     * linking to a metaservice.
     * Value: <code>metaservice-link</code>.
     */
    private static final String METASERVICE_LINK_NODE = "metaservice-link";
    
    private static final String UNIQUE_NAME_ATTR = "uniqueName";
    private static final String SOURCE_PROPERTY_ATTR = "sourceProperty";
    private static final String TARGET_ID_ATTR = "targetId";
    private static final String TARGET_METASERVICE_ATTR = "metaService";
    
    
    /** Hidden constructor. */
    private VirtualMetaPropertiesXMLConverter() {
        /* Hide the constructor. */
    }
    
    /**
     * Converts the XML document read from the reader object into a map
     * of virtual metaproperties.
     * 
     * @param is the input stream providing the XML
     * @param warningsHandler the handler for XML parsing messages.
     * @return the map of virtual metaproperties indexed by unique name. 
     * @throws SAXException if a parsing error occurs.
     * @throws InternalErrorException if a severe error occurs.
     */
    public static Map fromXML(InputStream is, WarningsHandler warningsHandler)
        throws SAXException, InternalErrorException {
        try {

            Document document =
                createDocument(
                    is,
                    new DefaultErrorHandler(warningsHandler));

            return buildVirtualMetaProperties(document.getDocumentElement());
        
        } catch (SAXException e) {
            throw e;
        } catch (Exception e) {
            throw new InternalErrorException(e);
        }
    }
    
    /**
     * Constructs a DOM Document corresponding to XML virtual metaproperties
     * definition provided by a input stream. The definition will be validated.
     * So, it must contain a reference to the corresponding DTD (or the DTD
     * itself embedded in the service specification). For error handling,
     * this method requires the parameter <code>errorHandler</code>,
     * specifying an instance of a concrete class implementing the interface
     * <code>ErrorHandler</code>. 
     *
     * @param  inputStream the input stream providing the XML service
     *         specification
     * @param  errorHandler an error handler
     * @return the DOM Document corresponding to XML service specification
     *         given in the input stream
     * @throws IOException if an I/O error occurs when reading from the
     *         input stream
     * @throws ParserConfigurationException if there was a configuration 
     *         problem related to the parser being used
     * @throws SAXException if any parse error occurs. It will be an
     *         instance of <code>org.xml.sax.SAXParseException</code> if the
     *         error is because of the document not being well-formed or the
     *         constraints formally specified in the DTD are violated. 
     *         Otherwise, it will be an instance of <code>SAXException</code>,
     *         representing a violated constraint not formally specified in
     *         the DTD (for example: a tag taking an illegal value).
     */
    /* TODO: Check if this code can be refactored. It is copied from 
     * MetaServiceXMLConverter, and a similar function exists in other
     * converters.
     */
    private static Document createDocument(
        InputStream inputStream,
        ErrorHandler errorHandler)
        throws IOException, ParserConfigurationException, SAXException {
        
        /* Get a DOM parser factory. */
        DocumentBuilderFactory documentBuilderFactory = 
            DocumentBuilderFactory.newInstance();

        /* Configure the factory:
         *
         * 1. Enable validation. 
         * 2. Make CDATA sections transparent to our code.
         * 3. Ignore comments
         * 4. Discard ignorable whitespace.
         *
         * NOTE: entity references are expanded by default.
         */
        documentBuilderFactory.setValidating(true);
        documentBuilderFactory.setCoalescing(true);
        documentBuilderFactory.setIgnoringComments(true);
        documentBuilderFactory.setIgnoringElementContentWhitespace(true);

        /* Create a DOM parser instance. */
        DocumentBuilder documentBuilder = 
            documentBuilderFactory.newDocumentBuilder();

        /* Configure the parser. */
        documentBuilder.setErrorHandler(errorHandler);    
        documentBuilder.setEntityResolver(
            new LocalEntityResolver(DTD_PUBLIC_ID, DTD_LOCAL_FILE_NAME));

        /* Get the "Document" object. */
        return documentBuilder.parse(inputStream);
    }

    /**
     * Creates the virtual metaproperties map from the given node.
     * @see #VIRTUAL_PROPERTIES_NODE
     * 
     * @param node the node to process.
     * @return the map of virtual properties indexed by unique name.
     * @throws SAXException if errors parsing the XML are found.
     * @throws InternalErrorException if severe errors occur.
     */
    private static Map buildVirtualMetaProperties(Node node)
        throws SAXException, InternalErrorException {
        
        Map result = new HashMap();
        NodeList children = node.getChildNodes();
        int childrenCount = children.getLength();
        for (int i = 0; i < childrenCount; i++) {
            IdentifiedMetaProperty pair = 
                buildVirtualMetaProperty(children.item(i));
            result.put(pair.getUniqueName(), pair.getMetaProperty());
        }
        return result;
    }
    
    /**
     * Multiplexing function. Idetifies responsible for processing
     * the given node to build a <code>MetaProperty</code> from it and
     * forwards the request.
     * <p> 
     * TODO: Use the Command pattern if this starts to grow.
     * @param node the node for building a virtual metaproperty.
     * @return the virtual metaproperty with the associated unique name.
     * @throws SAXException if parsing errors are found.
     * @throws InternalErrorException if severe errors are found.
     */
    private static IdentifiedMetaProperty buildVirtualMetaProperty(Node node) 
        throws SAXException, InternalErrorException {
        String nodeName = node.getNodeName();
        MetaProperty mp;
        if (nodeName.equals(METASERVICE_LINK_NODE)) {
            mp = buildMetaServiceLink(node);
        } else {
            throw new IllegalArgumentException(
                nodeName + " tag is not recognized.");
        }
        
        /* We know uniqueName is not null (it is validated using the DTD) */
        String uniqueName =
            node.getAttributes().getNamedItem(UNIQUE_NAME_ATTR).getNodeValue();
        
        /* Tag the metaproperty as virtual. */
        mp.getAnnotations().set(
            VirtualMetaPropertyAnnotationHelper.VIRTUAL_ANNOTATION,
            nodeName);
        return new IdentifiedMetaProperty(uniqueName, mp); 
    }

    /**
     * Creates and annotates a metaproperty linking to a metaservice.
     * @param node the node describing the link.
     * @return the metaproperty representing the link.
     * @throws SAXException if the referenced target metaproperty or 
     *      metaservice can't be found.
     * @throws InternalErrorException if a copy of the target metaproperty
     *      can't be found.
     */    
    private static MetaProperty buildMetaServiceLink(Node node) 
        throws InternalErrorException, SAXException {
        NamedNodeMap attrs = node.getAttributes();
        /* We know this won't be null (they are validated using the DTD. */
        String sourceMetaProperty =
            attrs.getNamedItem(SOURCE_PROPERTY_ATTR).getNodeValue();
        String targetMetaProperty =
            attrs.getNamedItem(TARGET_ID_ATTR).getNodeValue();
        String targetMetaService =
            attrs.getNamedItem(TARGET_METASERVICE_ATTR).getNodeValue();
            
        MetaService metaService =
            MetaServiceRegistrySingleton.getInstance().getMetaService(
                targetMetaService);

        /* Check that the metaservice exists. */
        if (metaService == null) {
            throw new SAXException(
                "Target metaservice " + targetMetaService + " is not known.");
        }
        /* Get the metaservice's table. It'll be the metaproperty's too. */
        String targetTable =
            SQLPersistenceTypeAnnotationHelper.getTableNameAnnotation(
                metaService);
        
        /* Copy the target service metaproperty. */
        MetaProperty metaProperty;
        try {
            metaProperty =
                (MetaProperty)Cloner.clone(metaService.getMetaRootProperty());
        } catch (IOException e) {
            throw new InternalErrorException(e);
        }
        /* Add annotations for the link. */
        Annotations annotations = metaProperty.getAnnotations();
        annotations.set(
            LinkMetaPropertyAnnotationHelper.SOURCE_PROPERTY_ANNOTATION,
            sourceMetaProperty);
        annotations.set(
            LinkMetaPropertyAnnotationHelper.TARGET_ID_ANNOTATION,
            targetMetaProperty);
        annotations.set(
            LinkMetaPropertyAnnotationHelper.TARGET_METASERVICE_ANNOTATION,
            targetMetaService);
        annotations.set(
            SQLPersistenceTypeAnnotationHelper.TABLE_NAME_ANNOTATION,
            targetTable);
        metaProperty.setAnnotations(annotations);
        return metaProperty;
    }
}

/**
 * Helper class to maintains associations between a virtual MetaProperty
 * and its unique name.
 * 
 * @author Abel Muinho
 * @since 1.0
 */
class IdentifiedMetaProperty {
    private String uniqueName;
    private MetaProperty metaProperty;
    
    /**
     * Creates an metaproperty and associated unique name pair.
     * @param uniqueName the unique name. Can't be <code>null</code>.
     * @param metaProperty the metaproperty. Can't be <code>null</code>.
     */
    public IdentifiedMetaProperty(String uniqueName, MetaProperty metaProperty) {
        if (uniqueName == null || metaProperty == null) {
            throw new IllegalArgumentException();
        }
        this.uniqueName = uniqueName;
        this.metaProperty = metaProperty;
    }
    
    /**
     * Obtains the unique name from the pair.
     * @return the unique name.
     */
    public String getUniqueName() {
        return uniqueName;
    }
    
    /**
     * Obtains the metaproperty from the pair.
     * @return the metaproperty.
     */
    public MetaProperty getMetaProperty() {
        return metaProperty;
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.