Package ariba.util.io

Source Code of ariba.util.io.FormattingSerializer

/*
    Copyright 1996-2009 Ariba, Inc.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

    $Id: //ariba/platform/util/core/ariba/util/io/FormattingSerializer.java#9 $
*/

package ariba.util.io;

import ariba.util.core.DebugState;
import ariba.util.core.OrderedHashtable;
import ariba.util.core.Sort;
import ariba.util.core.StringCompare;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
    Serializer subclass that formats and indents the ASCII generated
    by the Serializer. This class makes it possible to insert comments
    into a serialization.

    @aribaapi private
*/
public class FormattingSerializer extends Serializer
{
    private final int MAX_SIZE_FOR_SMALL_EXPRESSION = 80;

    private int indentationLength;
    private int tabLevel;
    private int nextCharIndex;

    /** Constructs a FormattingSerializer that writes to <b>writer</b>.
      */
    public FormattingSerializer (Writer writer)
    {
        super(writer);
        indentationLength = 4;
        tabLevel = 0;
        nextCharIndex = 0;
    }

    /**
        Sets the number of spaces to indent an expression. The default
        value is 4.
    */
    public void setIndentationLength (int numberOfSpaces)
    {
        indentationLength = numberOfSpaces;
    }

    /**
        Returns the number of spaces currently used to indent an expression.
    */
    public int indentationLength ()
    {
        return indentationLength;
    }

    /**
        Writes <b>aComment</b> to the FormattingSerializer's writer.
        Ignores all non-ASCII characters. If <b>cStyle</b> is
        <b>true</b>, the FormattingSerializer will use C-style
        delimiters, otherwise it will use C++-style delimiters ("//").
        <b>aComment</b> should not include comment delimiters.
    */
    public void writeComment (String aComment, boolean cStyle)
      throws IOException
    {
        int length = aComment.length();

        int delimiterSize;
        if (cStyle) {
            delimiterSize = 7;
        }
        else {
            delimiterSize = 4;
        }
        /* Does it fits on one line ? */
        if ((length + delimiterSize) <= (MAX_SIZE_FOR_SMALL_EXPRESSION -
                                         nextCharIndex) &&
           aComment.indexOf('\n') == -1)
        {
            if (cStyle) {
                writeCommentCharacter('/');
                writeCommentCharacter('*');
                writeCommentCharacter(' ');
            }
            else {
                writeCommentCharacter('/');
                writeCommentCharacter('/');
                writeCommentCharacter(' ');
            }
            for (int i=0; i < length ; i++) {
                writeCommentCharacter(aComment.charAt(i));
            }
            if (cStyle) {
                writeCommentCharacter(' ');
                writeCommentCharacter('*');
                writeCommentCharacter('/');
                writeCommentCharacter('\n');
            }
            else {
                writeCommentCharacter('\n');
            }
        }
        else {
            char ch;
            if (cStyle) {
                writeCommentCharacter('/');
                writeCommentCharacter('*');
                writeCommentCharacter('\n');
                writeCommentCharacter(' ');
                writeCommentCharacter('*');
                writeCommentCharacter(' ');
            }
            else {
                writeCommentCharacter('/');
                writeCommentCharacter('/');
                writeCommentCharacter(' ');
            }
            for (int i=0;i < length ; i++) {
                ch = aComment.charAt(i);
                if (ch == '\n') {
                    writeCommentCharacter('\n');
                    if (cStyle) {
                        writeCommentCharacter(' ');
                        writeCommentCharacter('*');
                        writeCommentCharacter(' ');
                    }
                    else {
                        writeCommentCharacter('/');
                        writeCommentCharacter('/');
                        writeCommentCharacter(' ');
                    }
                }
                else {
                    writeCommentCharacter(ch);
                }
            }
            if (cStyle) {
                writeCommentCharacter('\n');
                writeCommentCharacter(' ');
                writeCommentCharacter('*');
                writeCommentCharacter('/');
                writeCommentCharacter('\n');
            }
            else {
                writeCommentCharacter('\n');
            }
        }
    }

    private final void increaseTabLevel ()
    {
        tabLevel++;
    }

    private final void decreaseTabLevel ()
    {
        tabLevel--;
    }

    private final void insertNewLine () throws IOException
    {
        writeCharacter('\n');
        for (int i = 0, c = tabLevel * indentationLength(); i < c ; i++)
            writeCharacter(' ');
    }

    private final void writeCharacter (int c) throws IOException
    {
        super.writeOutput(c);
        if (c == '\n') {
            nextCharIndex=0;
        }
        else {
            nextCharIndex++;
        }
    }

    private final void writeCommentCharacter (int ch) throws IOException
    {
        if (ch >= 0x20 && ch < 0x7f) {
            writeCharacter(ch);
        }
        else {
            switch (ch) {
              case '\n':
              case '\t':
              case '\r':
                writeCharacter(ch);
            }
        }
    }

    private final int serializedStringFitsIn (String str, int maxSize)
    {
        if (str == null || str.length() == 0) {
            return 2;
        }

        int c = str.length();
        if (c > maxSize) {
            /*
                Ok in fact it is even more but it is greater than
                maxSize anyway
            */
            return c;
        }

        int length;
        if (stringRequiresQuotes(str)) {
            length = 2;
        }
        else {
            length = 0;
        }

        for (int i=0 ; i < c ; i++) {
            char ch = str.charAt(i);
            if (ch < 0xff) {
                if (ch >= '#' && ch <= '~' && ch != '\\') {
                    length++;
                }
                else switch (ch) {
                  case ' ':
                  case '!':
                    length++;
                    break;
                  case '"':
                  case '\t':
                  case '\n':
                  case '\r':
                  case '\\':
                    length+=2;
                    break;
                  default:
                    length+=4; /* Octal representation */
                }
            }
            else {
                /* Unicode */
                length += 6;
            }
            if (length > maxSize) {
                return length;
            }
        }
        return length;
    }

    private final int serializedMapFitsIn (Map h, int maxSize)
    {
        int length=2; /* for {
            and
        }
        */
        Iterator e = h.keySet().iterator();
        Object key;
        while (e.hasNext()) {
            key = e.next();
            length++; /* space */

            length += serializedObjectFitsIn(key, maxSize-length);
            if (length > maxSize) {
                return length;
            }

            length += 3; /* space=space */

            length += serializedObjectFitsIn(h.get(key), maxSize-length);
            length++; /* ; */
            if (length > maxSize) {
                return length;
            }
        }
        return length;
    }

    private final int serializedArrayFitsIn (Object a[], int maxSize)
    {
        int length = 3; /* [ space ] */
        for (int i = 0, c = a.length; i < c; i++) {
            length++; /* space */
            length += serializedObjectFitsIn(a[i], maxSize-length);
            if (length > maxSize) {
                return length;
            }
            if (i<(c-1)) { /* , */
                length++;
            }
        }
        return length;
    }

    private final int serializedListFitsIn (List v, int maxSize)
    {
        int length = 3; /* (space) */
        for (int i = 0, c = v.size(); i < c; i++) {
            length++; /* space */
            length += serializedObjectFitsIn(v.get(i), maxSize-length);
            if (length > maxSize) {
                return length;
            }
            if (i<(c-1)) { /* , */
                length++;
            }
        }
        return length;
    }

    private final int serializedNullFitsIn ()
    {
        return 1;
    }

    private final int serializedObjectFitsIn (Object anObject, int maxSize)
    {
        if (anObject instanceof String) {
            return serializedStringFitsIn((String)anObject, maxSize);
        }
        if (anObject instanceof Map) {
            return serializedMapFitsIn((Map)anObject, maxSize);
        }
        if (anObject instanceof Object[]) {
            return serializedArrayFitsIn((Object[])anObject, maxSize);
        }
        if (anObject instanceof List) {
            return serializedListFitsIn((List)anObject, maxSize);
        }
        if (anObject == null) {
            return serializedNullFitsIn();
        }
        return serializedStringFitsIn(anObject.toString(), maxSize);
    }

    private final boolean canFitExpressionOnLine (Object anObject)
    {
        int maxLength = MAX_SIZE_FOR_SMALL_EXPRESSION - nextCharIndex;
        return !(serializedObjectFitsIn(anObject, maxLength) > maxLength);
    }

    private final void formatList (List aList) throws IOException
    {
        int count = aList.size();
        if (canFitExpressionOnLine(aList)) {
            writeCharacter('(');
            for (int i=0 ; i < count ; i++) {
                writeCharacter(' ');
                formatObject(aList.get(i));
                if (i < (count-1)) {
                    writeCharacter(',');
                }
            }
            writeCharacter(' ');
            writeCharacter(')');
        }
        else {
            writeCharacter('(');
            increaseTabLevel();
            for (int i=0 ; i < count ; i++) {
                insertNewLine();
                formatObject(aList.get(i));
                if (i < (count-1)) {
                    writeCharacter(',');
                }
            }
            decreaseTabLevel();
            insertNewLine();
            writeCharacter(')');
        }
    }

    private final void formatArray (Object anArray[]) throws IOException
    {
        int count = anArray.length;
        if (canFitExpressionOnLine(anArray)) {
            writeCharacter('[');
            for (int i=0 ; i < count ; i++) {
                writeCharacter(' ');
                formatObject(anArray[i]);
                if (i < (count-1)) {
                    writeCharacter(',');
                }
            }
            writeCharacter(' ');
            writeCharacter(']');
        }
        else {
            writeCharacter('[');
            increaseTabLevel();
            for (int i=0 ; i < count ; i++) {
                insertNewLine();
                formatObject(anArray[i]);
                if (i < (count-1)) {
                    writeCharacter(',');
                }
            }
            decreaseTabLevel();
            insertNewLine();
            writeCharacter(']');
        }
    }

    private final void formatMap (Map h) throws IOException
    {
        int nonStringKeysCount=0;
        int stringCount=0;
        int count = h.size();
        String[] keys = new String[count];
        Object[] nonStringKeys = new Object[count];
        Iterator e = h.keySet().iterator();
        for (int i = 0; i < count; i++) {
            Object s = e.next();
            if (s instanceof String) {
                keys[stringCount++] = (String)s;
            }
            else {
                nonStringKeys[nonStringKeysCount++] = s;
            }
        }

        if (stringCount > 0) {
            if (!(h instanceof OrderedHashtable)) {
                Sort.objects(keys, null, null, 0, stringCount, StringCompare.self);
            }
            System.arraycopy(keys,
                             0,
                             nonStringKeys,
                             nonStringKeysCount,
                             stringCount);
        }
            // common code moved from then and else to here D107127
        writeCharacter('{');
        if (canFitExpressionOnLine(h)) {
            for (int i=0 ; i < count ; i++) {
                writeCharacter(' ');
                Object key = nonStringKeys[i];
                Object value = h.get(key);
                formatObject(key);
                writeCharacter(' '); writeCharacter('='); writeCharacter(' ');
                formatObject(value);
                writeCharacter(';');
            }
            writeCharacter('}');
        }
        else {
            increaseTabLevel();
            for (int i=0 ; i < count ; i++) {
                Object key = nonStringKeys[i];
                Object value = h.get(key);

                insertNewLine();
                formatObject(key);

                writeCharacter(' '); writeCharacter('='); writeCharacter(' ');

                formatObject(value);
                writeCharacter(';');
            }
            decreaseTabLevel();
            insertNewLine();
            writeCharacter('}');
        }
    }

    private final void formatObject (Object anObject) throws IOException
    {
        if (anObject instanceof String) {
            serializeString((String)anObject);
        }
        else if (anObject instanceof Map) {
            formatMap((Map)anObject);
        }
        else if (anObject instanceof Object[]) {
            formatArray((Object[])anObject);
        }
        else if (anObject instanceof List) {
            formatList((List)anObject);
        }
        else if (anObject instanceof DebugState) {
                // print the debug state if any. However if the debug
                // state is the object itself, just toString it.
            DebugState debugState = (DebugState)anObject;
            Object newObj = debugState.debugState();
            if (debugState == newObj) {
                serializeString(anObject.toString());
            }
            else {
                formatObject(newObj);
            }
        }
        else if (anObject == null) {
            serializeNull();
        }
        else {
            serializeString(anObject.toString());
        }
    }

    /** Overridden to produce a formatted serialization of <b>anObject</b>.
      */
    public void writeObject (Object anObject) throws IOException
    {
        formatObject(anObject);
    }

    /**
        Convenience method for generating <b>anObject</b>'s ASCII
        serialization. Returns <b>null</b> on error.
    */
    public static String serializeObject (Object anObject)
    {
        String result = null;
        if (anObject == null) {
            result = null;
        }
        else {
            StringWriter memory = new StringWriter();
            FormattingSerializer serializer = new FormattingSerializer(memory);

            try {
                serializer.writeObject(anObject);
                serializer.flush();
            }
            catch (IOException e) {
            }


            result = memory.toString();
            try {
                serializer.close();
                memory.close();
            }
            catch (IOException e) {
            }
            memory = null;
            serializer = null;
        }
        return result;
    }

    /**
        Convenience method for generating <b>anObject</b>'s ASCII serialization.
        This version will truncate the serialized object to about the maxLength.
        It will also add a warning message when truncation occurs.
        Returns <b>null</b> on empty input.
    */
    public static String serializeObject (Object anObject, int length)
    {
        String result = null;
        if (anObject == null) {
            result = null;
        }
        else {
            StringWriter memory = new TruncatingStringWriter(length);
            FormattingSerializer serializer = new FormattingSerializer(memory);

            try {
                serializer.writeObject(anObject);
                serializer.flush();
            }
            catch (TruncationException te) {
                // Truncation has occurred due to our size limit
                // The string already contains a warning that this happened.
                // Just ignore and continue.
            }
            catch (IOException e) {
            }


            result = memory.toString();
            try {
                serializer.close();
                memory.close();
            }
            catch (IOException e) {
            }
            memory = null;
            serializer = null;
        }
        return result;
    }

    /**
        Convenience method to format any ASCII serialization produced by a
        Serializer. Returns <b>null</b> on error.
    */
    public static String formatString (String input)
    {
        StringReader in = new StringReader(input);
        Object o;

        o = Deserializer.readObject(in);
        if (o != null) {
            StringWriter out = new StringWriter();
            FormattingSerializer serializer = new FormattingSerializer(out);
            try {
                serializer.writeObject(o);
                serializer.flush();
            }
            catch (IOException e) {
                return null;
            }
            return out.toString();
        }
        return null;
    }

    /**
        Convenience method for writing <b>anObject</b's ASCII
        serialization to <b>writer</b>. Returns <b>true</b> if
        the serialization and writing succeeds, rather than throwing
        an exception.
    */
    public static boolean writeObject (Writer writer,
                                       Object anObject)
    {
        FormattingSerializer serializer;

        try {
            serializer = new FormattingSerializer(writer);
            serializer.writeObject(anObject);
            serializer.flush();
        }
        catch (IOException e) {
            return false;
        }
        return true;
    }
}
TOP

Related Classes of ariba.util.io.FormattingSerializer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.