All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openmdx.base.naming.XRI_1Marshaller Maven / Gradle / Ivy

There is a newer version: 2.18.10
Show newest version
/*
 * ====================================================================
 * Project:     openMDX, http://www.openmdx.org/
 * Description: Path/XRI Marshaller 
 * Owner:       OMEX AG, Switzerland, http://www.omex.ch
 * ====================================================================
 *
 * This software is published under the BSD license as listed below.
 * 
 * Copyright (c) 2004-2010, OMEX AG, Switzerland
 * 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 openMDX team 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.
 * 
 * ------------------
 * 
 * This product includes software developed by other organizations as
 * listed in the NOTICE file.
 */
package org.openmdx.base.naming;

import java.util.ArrayList;

import org.openmdx.base.exception.ServiceException;
import org.openmdx.base.marshalling.Marshaller;
import org.openmdx.kernel.exception.BasicException;
import org.openmdx.kernel.xri.XRI_1Protocols;
import org.openmdx.kernel.xri.XRI_2Protocols;
import org.openmdx.kernel.xri.XRIAuthorities;

/**
 * Path/XRI Marshaller
 */
@SuppressWarnings({"rawtypes","unchecked"})
public final class XRI_1Marshaller
implements Marshaller
{

    private XRI_1Marshaller(
    ){
        // Avoid external instantiation
    }

    /**
     * Memorize the singleton
     */
    final static private Marshaller instance = new XRI_1Marshaller();

    /**
     * Return the singleton
     */
    static public Marshaller getInstance(
    ){
        return XRI_1Marshaller.instance;
    }


    //------------------------------------------------------------------------
    // Implements Marshaller
    //------------------------------------------------------------------------

    /**
     * Marshal a CharSequence[] into a CharSequence
     * 
     * @param     charSequences
     *            The array of CharSequences to be marshalled.
     * 
     * @return      A CharSequence containing the marshalled objects.
     */
    public Object marshal (
        Object charSequences
    ) throws ServiceException {
        if (charSequences == null) return null;
        Object[]source = (Object[])charSequences;
        StringBuilder xri = new StringBuilder(XRI_1Protocols.OPENMDX_PREFIX);
        char delimiter = ':';
        for(
                int i=0;
                i
     * 
  • Escape all percent "%" characters within a segment as "%25". * Escape unbalanced paranthesis within a segment as "%28" and "%29". *
  • Escape all number sign "#" characters that appear within a segment as "%23". *
  • Escape all question mark "?" characters that appear within a segment as "%3F". *
  • Escape all slash "/" characters that appear within a segment as "%2F". * * * @param charSequence * @param xri */ static void encode( String source, StringBuilder xri, boolean authority, boolean terminal ){ if(terminal && "%".equals(source)) { xri.append("***"); } else if(terminal && source.endsWith("%")) { xri.append(source.substring(0, source.length() - 1)).append("***"); } else if(authority && ":*".equals(source)){ xri.append("**"); } else if(source.startsWith(":") && source.endsWith("*")) { encode( source.substring(1, source.length() - 1), xri, false, false ); xri.append("**"); } else { for( int i = 0, l = source.length(); i < l; i++ ){ char character = source.charAt(i); switch (character) { case ':': xri.append(authority ? '.' : ':'); break; case '%': xri.append("%25"); break; case '{': case '}':case '<': case '>': case '[' : case ']': case ' ': case '"': case '\\': case '^': case '`': case '|': appendTo(xri, character, true); break; case '(': case ')': case '#': case '?': case '/': case ';': case '@': case '&': case '=': case '+': case '$': case ',': // remaining reserved case '-': case '_': case '.': case '!': case '~': case '*': case '\'': // remaining mark xri.append(character); break; default: if(Character.isLetterOrDigit(character)){ xri.append(character); } else { appendTo(xri, character, "%25"); } } } } } /** * Unmarshal a CharSequence into a CharSequence[]. * * @param marshalledObjects * A string containing a marshalled sequence of objects * * @return A String array containing the unmarshaled sequence * of objects. * @exception ServiceException ILLEGAL_ARGUMENT */ public Object unmarshal ( Object charSequence ) throws ServiceException { if (charSequence == null) return null; String source = SpecialResourceIdentifiers.unescapeResourceIdentifier(charSequence.toString()); if(!source.toLowerCase().startsWith(XRI_1Protocols.OPENMDX_PREFIX)) throw new ServiceException ( BasicException.Code.DEFAULT_DOMAIN, BasicException.Code.BAD_PARAMETER, "'xri' scheme and '" + XRIAuthorities.OPENMDX_AUTHORITY + "' authority expected", new BasicException.Parameter(BasicException.Parameter.XRI,source) ); ArrayList target = new ArrayList(); if(source.length() == XRI_1Protocols.OPENMDX_PREFIX.length()) { // Valid Empty Path } else if (":**".equals(source.substring(XRI_1Protocols.OPENMDX_PREFIX.length()))) { target.add(":*"); } else try { StringBuilder segment = new StringBuilder(); int crossReference = 0; boolean authority = true; for( int i = XRI_1Protocols.OPENMDX_PREFIX.length() + 1, limit = source.length(); i < limit; i++ ){ char character = source.charAt(i); switch(character){ case '(': ++crossReference; segment.append(character); break; case ')': if(--crossReference < 0) throw new ServiceException ( BasicException.Code.DEFAULT_DOMAIN, BasicException.Code.BAD_PARAMETER, "More closing than opening parenthesis", new BasicException.Parameter(BasicException.Parameter.XRI,source), new BasicException.Parameter("position",i) ); segment.append(character); break; case '/': if(crossReference > 0){ segment.append(character); } else { target.add( decode( segment.toString(), authority, false // terminal ) ); authority = false; segment.setLength(0); } break; case '.': segment.append( target.isEmpty() ? ':' : '.' ); break; default: segment.append(character); } } if(crossReference > 0) throw new ServiceException ( BasicException.Code.DEFAULT_DOMAIN, BasicException.Code.BAD_PARAMETER, "More opening than closing parenthesis", new BasicException.Parameter(BasicException.Parameter.XRI,source), new BasicException.Parameter("position", source.length()) ); target.add( decode( segment.toString(), authority, true // terminal ) ); } catch (Exception exception) { throw new ServiceException( exception, BasicException.Code.DEFAULT_DOMAIN, BasicException.Code.TRANSFORMATION_FAILURE, "XRI to Path conversion failed", new BasicException.Parameter(BasicException.Parameter.XRI, charSequence) ); } return target.toArray(new String[target.size()]); } /** * Decodes encoded ASCII characters only! * * @param source * @param authority * @param terminal * * @throws ServiceException */ private static String decode( String source, boolean authority, boolean terminal ) throws ServiceException{ if(source.startsWith(OPENMDX_XREF_PREFIX) && source.endsWith(XREF_END)) { StringBuilder target = new StringBuilder(); boolean xrefAuthority = true; for( int i = OPENMDX_XREF_PREFIX.length(), limit = source.length() - XREF_END.length(); i < limit; i++ ){ char character = source.charAt(i); switch (character) { case '%' : target.append( i + 2 < limit ? (char) Integer.parseInt(source.substring(++i, ++i+1), 0x10) : character ); break; case '.': target.append( xrefAuthority ? "::" : "." ); break; case '/': xrefAuthority = false; default: target.append(character); } } return new Path(target.toString()).toClassicRepresentation(); } else if (authority && "*".equals(source)) { return ":*"; } else if (terminal && ":***".equals(source)) { return "%"; } else if (terminal && source.endsWith("***")) { return decode(source.substring(0, source.length() - 3), authority, false) + "%"; } else if (source.endsWith("**")) { return ':' + decode( source.substring(0, source.length() - 2), authority, false ) + '*'; } else if (source.indexOf('%') < 0){ return source; } else { StringBuilder target = new StringBuilder(source.length()); for( int i = 0, limit = source.length(); i < limit; i++ ){ char character = source.charAt(i); target.append( character == '%' && i + 2 < limit ? (char) Integer.parseInt(source.substring(++i, ++i+1), 0x10) : character ); } return target.toString(); } } /** * Append a character or its escape sequence * * @param target * @param character * @param escaped */ private static void appendTo( StringBuilder target, char character, boolean escaped ){ if(escaped){ appendTo(target, character, "%"); } else { target.append(character); } } /** * Append an escape sequence * * @param target * @param character * @param escape */ private static void appendTo( StringBuilder target, char character, String escape ){ target.append( escape ).append( Character.toUpperCase(Character.forDigit(character / 0x10, 0x10)) ).append( Character.toUpperCase(Character.forDigit(character % 0x10, 0x10)) ); } private final static String XREF_BEGIN = "("; private final static String XREF_END = ")"; private final static String XRI_XREF_PREFIX = XREF_BEGIN + XRI_2Protocols.SCHEME_PREFIX; private final static String OPENMDX_XREF_PREFIX = XREF_BEGIN + XRIAuthorities.OPENMDX_AUTHORITY + ":"; }




  • © 2015 - 2024 Weber Informatics LLC | Privacy Policy