org.kalypso.core.catalog.DynamicCatalog.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.core.catalog.DynamicCatalog.java

Source

/*----------------    FILE HEADER KALYPSO ------------------------------------------
 *
 *  This file is part of kalypso.
 *  Copyright (C) 2004 by:
 *
 *  Technical University Hamburg-Harburg (TUHH)
 *  Institute of River and coastal engineering
 *  Denickestrae 22
 *  21073 Hamburg, Germany
 *  http://www.tuhh.de/wb
 *
 *  and
 *
 *  Bjoernsen Consulting Engineers (BCE)
 *  Maria Trost 3
 *  56070 Koblenz, Germany
 *  http://www.bjoernsen.de
 *
 *  This library 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 library 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 library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *  Contact:
 *
 *  E-Mail:
 *  belger@bjoernsen.de
 *  schlienger@bjoernsen.de
 *  v.doemming@tuhh.de
 *
 *  ---------------------------------------------------------------------------*/
package org.kalypso.core.catalog;

import java.io.File;
import java.io.FileWriter;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;

import oasis.names.tc.entity.xmlns.xml.catalog.Catalog;
import oasis.names.tc.entity.xmlns.xml.catalog.DelegateURI;
import oasis.names.tc.entity.xmlns.xml.catalog.NextCatalog;
import oasis.names.tc.entity.xmlns.xml.catalog.Public;
import oasis.names.tc.entity.xmlns.xml.catalog.System;

import org.apache.commons.io.IOUtils;
import org.kalypso.commons.bind.JaxbUtilities;
import org.kalypso.commons.java.io.FileUtilities;
import org.kalypso.contribs.java.net.UrlResolverSingleton;

/**
 * @author doemming
 */
public class DynamicCatalog implements ICatalog {
    /**
     * system entry matches the specified system identifier, it is used
     */
    private static final int SYSTEM_RESOLVE_1 = 1;

    /**
     * system entry matches the specified system identifier of <i>imported</i> catalogs (next catalog), it is used
     */
    private static final int SYSTEM_RESOLVE_NEXT_CATALOG_2 = 2;

    /**
     * no system entry matches the specified system identifier<br>
     * but a rewrite entry matches, it is used
     */
    private static final int SYSTEM_REWRITE_3 = 3;

    /**
     * public entry matches the specified public identifier and either prefer is public or no system identifier is
     * provided, it is used.
     */
    private static final int PUBLIC_RESOLVE_4 = 4;

    /**
     * no exact match was found, but it matches one or more of the partial identifiers specified in delegates entries, the
     * delegate catalogs are searched for a matching identifier
     */
    private static final int DELEGATE_SEARCH_5 = 5;

    private final Catalog m_catalog;

    private URL m_context = null;

    private final CatalogManager m_manager;

    protected DynamicCatalog(final CatalogManager manager, final URL context, final Catalog catalog) {
        m_manager = manager;
        m_catalog = catalog;
        m_context = context;
    }

    public String getCatalogID() {
        return m_catalog.getId();
    }

    public String getBase() {
        final Map<QName, String> otherAttributes = m_catalog.getOtherAttributes();
        return otherAttributes.get(CatalogUtilities.BASE);
    }

    private void internalAddEntry(String uri, final String systemID, final String publicID,
            final boolean relative) {
        // TODO check if entry already exists
        if (uri == null || uri.length() < 1)
            throw new UnsupportedOperationException();
        if (relative) {
            try {
                final URI uri2 = new URI(uri);
                final String absolute = uri2.toURL().toExternalForm();
                final String relativePath = FileUtilities.getRelativePathTo(m_context.toExternalForm(), absolute);
                uri = relativePath;
            } catch (final Exception e) {
                // no
            }
        }
        final List<Object> publicOrSystemOrUri = m_catalog.getPublicOrSystemOrUri();
        if (systemID != null && systemID.length() > 0) {
            final System system = CatalogManager.OBJECT_FACTORY_CATALOG.createSystem();
            system.setSystemId(systemID);
            system.setUri(uri);
            publicOrSystemOrUri.add(CatalogManager.OBJECT_FACTORY_CATALOG.createSystem(system));
        }
        if (publicID != null && publicID.length() > 0) {
            final Public public_ = CatalogManager.OBJECT_FACTORY_CATALOG.createPublic();
            public_.setPublicId(publicID);
            public_.setUri(uri);
            publicOrSystemOrUri.add(CatalogManager.OBJECT_FACTORY_CATALOG.createPublic(public_));
        }

    }

    /**
     * @see org.kalypso.core.catalog.ICatalog#addNextCatalog(java.net.URL)
     */
    @Override
    public void addNextCatalog(final URL catalogURL) {
        final List<Object> publicOrSystemOrUri = m_catalog.getPublicOrSystemOrUri();
        final NextCatalog nextCatalog = CatalogManager.OBJECT_FACTORY_CATALOG.createNextCatalog();
        nextCatalog.setCatalog(catalogURL.toExternalForm());
        final JAXBElement<NextCatalog> element = CatalogManager.OBJECT_FACTORY_CATALOG
                .createNextCatalog(nextCatalog);
        publicOrSystemOrUri.add(element);
    }

    /**
     * @see org.kalypso.core.catalog.ICatalog#addEntry(java.lang.String, java.lang.String, java.lang.String)
     */
    @Override
    public void addEntry(final String uri, final String systemID, final String publicID) {
        if (systemID != null && !"".equals(systemID)) //$NON-NLS-1$
            addEntry(uri, systemID, SYSTEM_ID, false);
        if (publicID != null && !"".equals(publicID)) //$NON-NLS-1$
            addEntry(uri, publicID, PUBLIC_ID, false);
    }

    private static final int SYSTEM_ID = 1;

    private static final int PUBLIC_ID = 2;

    /**
     * @see org.kalypso.core.catalog.ICatalog#addEntryRelative(java.lang.String, java.lang.String, java.lang.String)
     */
    @Override
    public void addEntryRelative(final String uri, final String systemID, final String publicID) {
        if (systemID != null && !"".equals(systemID)) //$NON-NLS-1$
            addEntry(uri, systemID, SYSTEM_ID, true);
        if (publicID != null && !"".equals(publicID)) //$NON-NLS-1$
            addEntry(uri, publicID, PUBLIC_ID, true);
    }

    @SuppressWarnings("unchecked") //$NON-NLS-1$
    private void addEntry(final String uri, final String entryID, final int entryType, final boolean relative) {
        if (entryID == null || "".equals(entryID)) //$NON-NLS-1$
            return;
        if (!entryID.startsWith("urn:")) //$NON-NLS-1$
        {
            switch (entryType) {
            case SYSTEM_ID:
                internalAddEntry(uri, entryID, null, relative);
                break;
            case PUBLIC_ID:
                internalAddEntry(uri, null, entryID, relative);
                break;
            default:
                throw new UnsupportedOperationException();
            }
            return;
        }
        final int max = CatalogUtilities.getMaxLevel(entryID);
        final String baseURN = CatalogUtilities.getUrnSection(entryID, 1, max - 1) + ":"; //$NON-NLS-1$
        // check the internal policy for our dynamic catalogs

        // either
        // 1. the requested catalog is this catalog
        // or
        // 2. it is a delegated catalog

        // check 1: this catalog ?
        final String myBaseURN = getBase();
        if (myBaseURN.equals(baseURN)) {
            switch (entryType) {
            case SYSTEM_ID:
                internalAddEntry(uri, entryID, null, relative);
                break;
            case PUBLIC_ID:
                internalAddEntry(uri, null, entryID, relative);
                break;
            default:
                throw new UnsupportedOperationException();
            }
            return;
        }

        // check 2: a delegate ?
        final List<Object> publicOrSystemOrUri = m_catalog.getPublicOrSystemOrUri();
        for (final Object object : publicOrSystemOrUri) {
            final Object item = ((JAXBElement<Object>) object).getValue();
            if (item instanceof DelegateURI) {
                final DelegateURI delegateURI = (DelegateURI) item;
                final String uriStartString = delegateURI.getUriStartString();
                if (baseURN.startsWith(uriStartString)) {
                    // delegate matches
                    final String catalogID = delegateURI.getCatalog();
                    final String uriToCatalog = resolve(catalogID, catalogID);
                    final ICatalog catalog;
                    try {
                        catalog = m_manager.getCatalog(new URI(uriToCatalog));
                        switch (entryType) {
                        case SYSTEM_ID:
                            if (relative)
                                catalog.addEntryRelative(uri, entryID, null);
                            else
                                catalog.addEntry(uri, entryID, null);
                            break;
                        case PUBLIC_ID:
                            if (relative)
                                catalog.addEntryRelative(uri, null, entryID);
                            else
                                catalog.addEntry(uri, null, entryID);
                            break;
                        default:
                            throw new UnsupportedOperationException();
                        }
                        return;
                    } catch (final URISyntaxException e) {
                        e.printStackTrace();
                        throw new UnsupportedOperationException(e);
                    }
                }
            }
        }

        // catalog seems to be non existing
        final int maxLevel = CatalogUtilities.getMaxLevel(myBaseURN);
        final String urnSection = CatalogUtilities.getUrnSection(baseURN, maxLevel + 1);
        final String newCatalogURIBase = CatalogUtilities.addURNSection(myBaseURN, urnSection) + ":"; //$NON-NLS-1$
        final String newCatalogURN = CatalogUtilities.createCatalogURN(newCatalogURIBase);
        try {
            m_manager.ensureExisting(newCatalogURIBase);
        } catch (final Exception e) {
            e.printStackTrace();
            throw new UnsupportedOperationException(e);
        }

        // create a delegate to a new catalog
        // the catalog will be created on demand
        final DelegateURI catalogURIEntry = CatalogManager.OBJECT_FACTORY_CATALOG.createDelegateURI();
        catalogURIEntry.setUriStartString(newCatalogURIBase);
        catalogURIEntry.setCatalog(newCatalogURN);
        publicOrSystemOrUri.add(CatalogManager.OBJECT_FACTORY_CATALOG.createDelegateURI(catalogURIEntry));

        final System catalogSystemEntry = CatalogManager.OBJECT_FACTORY_CATALOG.createSystem();
        catalogSystemEntry.setSystemId(newCatalogURN);
        catalogSystemEntry.setUri(urnSection + "/" + CatalogUtilities.CATALOG_FILE_NAME); //$NON-NLS-1$
        publicOrSystemOrUri.add(CatalogManager.OBJECT_FACTORY_CATALOG.createSystem(catalogSystemEntry));
        // next time catalog will be available
        addEntry(uri, entryID, entryType, relative);
    }

    /**
     * resolve relative to the catalog, used to resolve relative uri-entries inside the catalog
     */
    private URL resolve(final String href) throws MalformedURLException {
        return UrlResolverSingleton.resolveUrl(m_context, href);
    }

    @Override
    public String resolve(final String systemID, final String publicID) {
        return resolve(systemID, publicID, true);
    }

    @Override
    public String resolve(final String systemID, final String publicID, final boolean resolveContext) {
        return resolveLocal(systemID, publicID, false, resolveContext);
    }

    private String resolveLocal(final String systemID, final String publicID, final boolean local,
            final boolean resolveContext) {
        final List<String> result = internResolve(systemID, publicID, null, false, false, local, resolveContext);
        if (result.size() > 0)
            return result.get(0);
        return systemID;
    }

    /**
     * @see org.kalypso.core.catalog.ICatalog#getEnryURNS(java.lang.String)
     */
    @Override
    public List<String> getEntryURNS(final String urnPattern) {
        return internResolve(urnPattern, urnPattern, null, true, true, false, true);
    }

    /**
     * @return true results of resolve
     */
    private List<String> internResolveDelegate(final String hrefCatalog, final String systemID,
            final String publicID, List<String> collector, final boolean doCollectURN, final boolean supportPattern,
            final boolean resolveContext) {
        final String uriToCatalog = resolveLocal(hrefCatalog, hrefCatalog, true, true);
        final URI catalogURI;
        try {
            final URL url = new URL(uriToCatalog);
            catalogURI = url.toURI();
            final ICatalog catalog = m_manager.getCatalog(catalogURI);
            if (catalog instanceof DynamicCatalog) {
                final DynamicCatalog dynCatalog = (DynamicCatalog) catalog;
                collector = dynCatalog.internResolve(systemID, publicID, collector, doCollectURN, supportPattern,
                        false, resolveContext);
            } else if (catalog == null) {
                java.lang.System.out.println("oups"); //$NON-NLS-1$
            } else {
                if (doCollectURN) {
                    final String uriFromSystemID = catalog.resolve(systemID, null);
                    if (systemID != null && !systemID.equals(uriFromSystemID))
                        collector.add(systemID);
                    final String uriFromPublicID = catalog.resolve(null, publicID);
                    if (publicID != null && !publicID.equals(uriFromPublicID))
                        collector.add(publicID);
                } else {
                    final String uri = catalog.resolve(systemID, publicID);
                    collector.add(uri);
                }
            }

        } catch (final URISyntaxException e) {
            // invalid catalog entry
            e.printStackTrace();
        } catch (final MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return collector;
    }

    /**
     * @param resolveContext
     *          If true, the found entry is resolved against the catalogs location, if false it is directly returned.
     */
    @SuppressWarnings("unchecked") //$NON-NLS-1$
    private List<String> internResolve(final String systemID, final String publicID, List<String> collector,
            final boolean doCollectURN, final boolean supportPattern, final boolean local,
            final boolean resolveContext) {
        if (collector == null)
            collector = new ArrayList<>();

        final List<Object> publicOrSystemOrUri = m_catalog.getPublicOrSystemOrUri();
        final List<Object> entries = new ArrayList<>();
        entries.addAll(publicOrSystemOrUri);
        // TODO add entries from imported catalogs or extension-point catalogs
        for (int step = SYSTEM_RESOLVE_1; step <= DELEGATE_SEARCH_5; step++) {
            for (final Object entry : entries) {
                final Object item = ((JAXBElement<Object>) entry).getValue();
                switch (step) {
                case SYSTEM_RESOLVE_1:
                    if (item instanceof System && systemID != null) {
                        final System system = (System) item;
                        final String sysID = system.getSystemId();
                        if (matches(systemID, sysID, supportPattern)) {
                            try {
                                if (doCollectURN)
                                    collector.add(sysID);
                                else if (!resolveContext) {
                                    collector.add(system.getUri());
                                    return collector;
                                } else {
                                    final String uri = resolve(system.getUri()).toExternalForm();
                                    collector.add(uri);
                                    return collector;
                                }
                            } catch (final Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    break;
                case SYSTEM_RESOLVE_NEXT_CATALOG_2:
                    if (item instanceof NextCatalog && !local) {
                        final NextCatalog nextCatalog = (NextCatalog) item;
                        final String catalogHref = nextCatalog.getCatalog();
                        // TODO: @Andreas: is it ok to stop here if we find something? What, if we have some public/system entries
                        // after the nextCatalog entry?
                        collector = internResolveDelegate(catalogHref, systemID, publicID, collector, doCollectURN,
                                supportPattern, resolveContext);
                        if (!doCollectURN && collector.size() > 0)
                            return collector;
                    }
                    break;
                case SYSTEM_REWRITE_3:
                    // TODO
                    break;
                case PUBLIC_RESOLVE_4:
                    if (item instanceof Public && publicID != null) {
                        final Public public_ = (Public) item;
                        final String pubID = public_.getPublicId();
                        if (matches(publicID, pubID, supportPattern)) {
                            try {
                                if (doCollectURN)
                                    collector.add(pubID);
                                else if (!resolveContext) {
                                    collector.add(public_.getUri());
                                    return collector;
                                } else {
                                    final String uri = resolve(public_.getUri()).toExternalForm();
                                    collector.add(uri);
                                    return collector;
                                }
                            } catch (final MalformedURLException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    break;
                case DELEGATE_SEARCH_5:
                    if (item instanceof DelegateURI && !local) {
                        final DelegateURI delegateURI = (DelegateURI) item;
                        final String uriStartString = delegateURI.getUriStartString();
                        if (systemID != null && systemID.startsWith(uriStartString) //
                                || //
                                publicID != null && publicID.startsWith(uriStartString)) {
                            final String catalogHref = delegateURI.getCatalog();
                            collector = internResolveDelegate(catalogHref, systemID, publicID, collector,
                                    doCollectURN, supportPattern, resolveContext);
                            if (!doCollectURN && collector.size() > 0)
                                return collector;
                        }
                    }
                    break;
                default:
                    break;
                }
            }
        }
        return collector;
    }

    private boolean matches(final String requestedID, final String entryID, final boolean supportPattern) {
        if (!supportPattern)
            return requestedID.equals(entryID);
        if (requestedID.endsWith("*")) //$NON-NLS-1$
        {
            final String prefixToTest = requestedID.substring(0, requestedID.length() - 1);
            return entryID.startsWith(prefixToTest);
        } else {
            final String[] requestedStrings = requestedID.split(":"); //$NON-NLS-1$
            final String[] entryStrings = entryID.split(":"); //$NON-NLS-1$
            if (requestedStrings.length == entryStrings.length) {
                for (int i = 0; i < entryStrings.length; i++) {
                    final String requestedString = requestedStrings[i];
                    if (!requestedString.equals("*") && !requestedString.equals(entryStrings[i])) //$NON-NLS-1$
                        return false;
                }
                return true;
            }
        }

        return requestedID.equals(entryID);
    }

    void save(final File baseDir) throws Exception {
        final Marshaller marshaller = JaxbUtilities.createMarshaller(CatalogManager.JAX_CONTEXT_CATALOG);
        final String catalogBaseURN = getBase();
        final String path = CatalogUtilities.getPathForCatalog(catalogBaseURN);
        FileWriter writer = null;
        try {
            final File file = new File(baseDir, path);
            final File parent = file.getParentFile();
            if (!parent.exists())
                parent.mkdirs();
            writer = new FileWriter(file);
            final JAXBElement<Catalog> root = CatalogManager.OBJECT_FACTORY_CATALOG.createCatalog(m_catalog);
            marshaller.marshal(root, writer);
        } catch (final Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            IOUtils.closeQuietly(writer);
        }
    }

    public URL getLocation() {
        return m_context;
    }

    /**
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "XML-Catalog: \n ID=" + m_catalog.getId().toString() + "\n Base=" + getBase() + "\n context: " //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                + m_context.toString();
    }

}