    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
    043package org.jfree.xml.generator;
    044
    045import java.io.BufferedWriter;
    046import java.io.File;
    047import java.io.FileOutputStream;
    048import java.io.IOException;
    049import java.io.OutputStreamWriter;
    050import java.util.ArrayList;
    051import java.util.Arrays;
    052import java.util.Iterator;
    053
    054import org.jfree.io.IOUtils;
    055import org.jfree.util.HashNMap;
    056import org.jfree.util.Log;
    057import org.jfree.xml.generator.model.ClassDescription;
    058import org.jfree.xml.generator.model.DescriptionModel;
    059import org.jfree.xml.generator.model.ManualMappingInfo;
    060import org.jfree.xml.generator.model.MappingModel;
    061import org.jfree.xml.generator.model.MultiplexMappingInfo;
    062import org.jfree.xml.util.ClassModelTags;
    063
    064/**
    065 * A model writer that writes to multiple files.
    066 */
    067public 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}