    001    /* ========================================================================
    002     * JCommon : a free general purpose class library for the Java(tm) platform
    003     * ========================================================================
    004     *
    005     * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
    006     *
    007     * Project Info:  http://www.jfree.org/jcommon/index.html
    008     *
    009     * This library is free software; you can redistribute it and/or modify it
    010     * under the terms of the GNU Lesser General Public License as published by
    011     * the Free Software Foundation; either version 2.1 of the License, or
    012     * (at your option) any later version.
    013     *
    014     * This library is distributed in the hope that it will be useful, but
    015     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    016     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    017     * License for more details.
    018     *
    019     * You should have received a copy of the GNU Lesser General Public
    020     * License along with this library; if not, write to the Free Software
    021     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
    022     * USA.
    023     *
    024     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
    025     * in the United States and other countries.]
    026     *
    027     * -------------------------
    028     * SplittingModelWriter.java
    029     * -------------------------
    030     * (C)opyright 2003, by Thomas Morgner and Contributors.
    031     *
    032     * Original Author:  Thomas Morgner;
    033     * Contributor(s):   David Gilbert (for Object Refinery Limited);
    034     *
    035     * $Id: SplittingModelWriter.java,v 1.2 2005/10/18 13:32:20 mungady Exp $
    036     *
    037     * Changes
    038     * -------------------------
    039     * 12.11.2003 : Initial version
    040     *
    041     */
    042
    043    package org.jfree.xml.generator;
    044
    045    import java.io.BufferedWriter;
    046    import java.io.File;
    047    import java.io.FileOutputStream;
    048    import java.io.IOException;
    049    import java.io.OutputStreamWriter;
    050    import java.util.ArrayList;
    051    import java.util.Arrays;
    052    import java.util.Iterator;
    053
    054    import org.jfree.io.IOUtils;
    055    import org.jfree.util.HashNMap;
    056    import org.jfree.util.Log;
    057    import org.jfree.xml.generator.model.ClassDescription;
    058    import org.jfree.xml.generator.model.DescriptionModel;
    059    import org.jfree.xml.generator.model.ManualMappingInfo;
    060    import org.jfree.xml.generator.model.MappingModel;
    061    import org.jfree.xml.generator.model.MultiplexMappingInfo;
    062    import org.jfree.xml.util.ClassModelTags;
    063
    064    /**
    065     * A model writer that writes to multiple files.
    066     */
    067    public class SplittingModelWriter extends ModelWriter {
    068
    069        /** ??. */
    070        private HashNMap classDescriptionByPackage;
    071
    072        /** The sources. */
    073        private ArrayList sources;
    074
    075        /** The target file. */
    076        private File targetFile;
    077
    078        /** The file extension. */
    079        private String extension;
    080
    081        /** The plain file name. */
    082        private String plainFileName;
    083
    084        /** ??. */
    085        private HashNMap manualMappingByPackage;
    086
    087        /** ??. */
    088        private HashNMap multiplexMappingByPackage;
    089
    090        /**
    091         * Creates a new instance.
    092         */
    093        public SplittingModelWriter() {
    094            super();
    095        }
    096
    097        /**
    098         * Writes the model to the specified target.
    099         *
    100         * @param target  the target file name.
    101         *
    102         * @throws IOException if there is an I/O problem.
    103         */
    104        public synchronized void write(final String target) throws IOException {
    105
    106            final DescriptionModel model = getModel();
    107            this.sources = new ArrayList(Arrays.asList(model.getSources()));
    108            this.targetFile = new File(target);
    109            this.plainFileName = IOUtils.getInstance().stripFileExtension(this.targetFile.getName());
    110            this.extension = IOUtils.getInstance().getFileExtension(target);
    111
    112            // split into classDescriptionByPackage ...
    113            this.classDescriptionByPackage = new HashNMap();
    114            for (int i = 0; i < model.size(); i++) {
    115                final ClassDescription cd = model.get(i);
    116                if (cd.getSource() == null) {
    117                    final String packageName = getPackage(cd.getObjectClass());
    118                    final String includeFileName = this.plainFileName + "-" + packageName
    119                        + this.extension;
    120                    this.classDescriptionByPackage.add(includeFileName, cd);
    121                }
    122                else {
    123                    this.classDescriptionByPackage.add(cd.getSource(), cd);
    124                }
    125            }
    126
    127            final MappingModel mappingModel = model.getMappingModel();
    128
    129            // split manual mappings into packages ...
    130            final ManualMappingInfo[] manualMappings = mappingModel.getManualMapping();
    131            this.manualMappingByPackage = new HashNMap();
    132            for (int i = 0; i < manualMappings.length; i++) {
    133                final ManualMappingInfo mapping = manualMappings[i];
    134                if (mapping.getSource() == null) {
    135                    this.manualMappingByPackage.add("", mapping);
    136                }
    137                else {
    138                    this.manualMappingByPackage.add(mapping.getSource(), mapping);
    139                }
    140            }
    141
    142            // split manual mappings into packages ...
    143            final MultiplexMappingInfo[] multiplexMappings = mappingModel.getMultiplexMapping();
    144            this.multiplexMappingByPackage = new HashNMap();
    145            for (int i = 0; i < multiplexMappings.length; i++) {
    146                final MultiplexMappingInfo mapping = multiplexMappings[i];
    147                if (mapping.getSource() == null) {
    148                    this.multiplexMappingByPackage.add("", mapping);
    149                }
    150                else {
    151                    this.multiplexMappingByPackage.add(mapping.getSource(), mapping);
    152                }
    153            }
    154
    155
    156            final Object[] keys = this.classDescriptionByPackage.keySet().toArray();
    157            for (int i = 0; i < keys.length; i++) {
    158
    159                final String includeFileName = (String) keys[i];
    160                // write if not contained in the master file ...
    161                if (!includeFileName.equals("")) {
    162                    writePackageFile(includeFileName);
    163                }
    164            }
    165
    166            writeMasterFile();
    167
    168            this.manualMappingByPackage = null;
    169            this.multiplexMappingByPackage = null;
    170            this.classDescriptionByPackage = null;
    171            this.sources = null;
    172        }
    173
    174        /**
    175         * Writes a file for a package.
    176         *
    177         * @param includeFileName  the name of the file.
    178         *
    179         * @throws IOException if there is an I/O problem.
    180         */
    181        private void writePackageFile(final String includeFileName) throws IOException {
    182
    183            final Iterator values = this.classDescriptionByPackage.getAll(includeFileName);
    184            final Iterator manualMappings = this.manualMappingByPackage.getAll(includeFileName);
    185            final Iterator multiplexMappings = this.multiplexMappingByPackage.getAll(includeFileName);
    186            if (!values.hasNext() && !manualMappings.hasNext() && !multiplexMappings.hasNext()) {
    187                return;
    188            }
    189
    190            Log.debug ("Writing included file: " + includeFileName);
    191            // the current file need no longer be included manually ...
    192            this.sources.remove(includeFileName);
    193
    194            final BufferedWriter writer = new BufferedWriter(
    195                new OutputStreamWriter(
    196                    new FileOutputStream(
    197                        new File(this.targetFile.getParentFile(), includeFileName)
    198                    ),
    199                    "UTF-8"
    200                )
    201            );
    202
    203            writeXMLHeader(writer);
    204            writeStandardComment(writer, getModel().getModelComments());
    205            getWriterSupport().writeTag(writer, ClassModelTags.OBJECTS_TAG);
    206
    207            while (values.hasNext()) {
    208                final ClassDescription cd = (ClassDescription) values.next();
    209                writeClassDescription(writer, cd);
    210            }
    211
    212
    213            while (manualMappings.hasNext()) {
    214                final ManualMappingInfo mi = (ManualMappingInfo) manualMappings.next();
    215                writeManualMapping(writer, mi);
    216            }
    217
    218            while (multiplexMappings.hasNext()) {
    219                final MultiplexMappingInfo mi = (MultiplexMappingInfo) multiplexMappings.next();
    220                writeMultiplexMapping(writer, mi);
    221            }
    222
    223            writeCloseComment(writer, getModel().getModelComments());
    224            getWriterSupport().writeCloseTag(writer, ClassModelTags.OBJECTS_TAG);
    225            writer.close();
    226        }
    227
    228        /**
    229         * Returns the name of the package for the given class. This is a
    230         * workaround for the classloader behaviour of JDK1.2.2 where no
    231         * package objects are created.
    232         *
    233         * @param c the class for which we search the package.
    234         *
    235         * @return the name of the package, never null.
    236         */
    237        public static String getPackage(final Class c) {
    238            final String className = c.getName();
    239            final int idx = className.lastIndexOf('.');
    240            if (idx <= 0) {
    241                // the default package
    242                return "";
    243            }
    244            else {
    245                return className.substring(0, idx);
    246            }
    247        }
    248
    249        /**
    250         * Writes the master file.
    251         *
    252         * @throws IOException if there is an I/O problem.
    253         */
    254        private void writeMasterFile() throws IOException {
    255
    256            Log.debug ("Writing master file: " + this.targetFile);
    257
    258            final BufferedWriter writer = new BufferedWriter(
    259                new OutputStreamWriter(new FileOutputStream(this.targetFile), "UTF-8")
    260            );
    261
    262            writeXMLHeader(writer);
    263            writeStandardComment(writer, getModel().getModelComments());
    264            getWriterSupport().writeTag(writer, ClassModelTags.OBJECTS_TAG);
    265
    266            for (int i = 0; i < this.sources.size(); i++) {
    267                final String includeFileName = (String) this.sources.get(i);
    268                if (!includeFileName.equals("")) {
    269                    writeTag(writer, ClassModelTags.INCLUDE_TAG, ClassModelTags.SOURCE_ATTR,
    270                        includeFileName, getModel().getIncludeComment(includeFileName));
    271                }
    272            }
    273
    274            final Object[] keys = this.classDescriptionByPackage.keySet().toArray();
    275            Arrays.sort(keys);
    276            for (int i = 0; i < keys.length; i++) {
    277                final String includeFileName = (String) keys[i];
    278                if (!includeFileName.equals("")) {
    279                    writeTag(writer, ClassModelTags.INCLUDE_TAG, ClassModelTags.SOURCE_ATTR,
    280                        includeFileName, getModel().getIncludeComment(includeFileName));
    281                }
    282            }
    283
    284            final Iterator values = this.classDescriptionByPackage.getAll("");
    285            while (values.hasNext()) {
    286                final ClassDescription cd = (ClassDescription) values.next();
    287                writeClassDescription(writer, cd);
    288            }
    289
    290            final Iterator manualMappings = this.manualMappingByPackage.getAll("");
    291            while (manualMappings.hasNext()) {
    292                final ManualMappingInfo mi = (ManualMappingInfo) manualMappings.next();
    293                writeManualMapping(writer, mi);
    294            }
    295
    296            final Iterator multiplexMappings = this.multiplexMappingByPackage.getAll("");
    297            while (multiplexMappings.hasNext()) {
    298                final MultiplexMappingInfo mi = (MultiplexMappingInfo) multiplexMappings.next();
    299                writeMultiplexMapping(writer, mi);
    300            }
    301
    302            writeCloseComment(writer, getModel().getModelComments());
    303            getWriterSupport().writeCloseTag(writer, ClassModelTags.OBJECTS_TAG);
    304            writer.close();
    305        }
    306
    307    }