forked from geodmms/xdgnjobs

?? ?
2008-05-06 0ffea4eece9090db61ff0042ac26a6cb2a356cab
update for EOFM-73
6 files modified
6 files added
5029 ■■■■■ changed files
.gitattributes 6 ●●●●● patch | view | raw | blame | history
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractDgnFileJobContext.java 71 ●●●●● patch | view | raw | blame | history
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java 49 ●●●●● patch | view | raw | blame | history
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleJobContext.java 21 ●●●●● patch | view | raw | blame | history
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/GeneralDgnConvertJobContext.java 43 ●●●●● patch | view | raw | blame | history
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/IndexDgnConvertJobContext.java 269 ●●●●● patch | view | raw | blame | history
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java 293 ●●●●● patch | view | raw | blame | history
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertJobContext.java 36 ●●●● patch | view | raw | blame | history
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Base64.java 551 ●●●●● patch | view | raw | blame | history
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/StringUtils.java 2923 ●●●●● patch | view | raw | blame | history
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TPCLIDConverter.java 758 ●●●●● patch | view | raw | blame | history
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java 9 ●●●● patch | view | raw | blame | history
.gitattributes
@@ -56,13 +56,17 @@
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeCompIdDispatchableFilter.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeCompLevelIdDispatchableFilter.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/TypeIdDispatchableFilter.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractDgnFileJobContext.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleJobContext.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/GeneralDgnConvertJobContext.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/IndexDgnConvertJobContext.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertJobContext.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleUpgradeBlob2UDTJob.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleUpgradeJobContext.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/TWD97GeometryConverterDecorator.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Base64.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/BinConverter.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Bits.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/ByteArrayCompressor.java svneol=native#text/plain
@@ -71,6 +75,8 @@
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/GeomUtil.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/LangUtil.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/PrintfFormat.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/StringUtils.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TPCLIDConverter.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java svneol=native#text/plain
xdgnjobs/ximple-spatialjob/src/main/resources/com/ximple/eofms/filter/ElementDispatcherRules.xml svneol=native#text/xml
xdgnjobs/ximple-spatialjob/src/main/resources/conf/ConvertShpFilterForLayer.xml svneol=native#text/xml
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractDgnFileJobContext.java
New file
@@ -0,0 +1,71 @@
package com.ximple.eofms.jobs;
import java.util.Properties;
import org.quartz.JobExecutionContext;
import com.ximple.io.dgn7.Dgn7fileReader;
public abstract class AbstractDgnFileJobContext
{
    /**
     * Encoding of URL path.
     */
    protected static final String ENCODING = "UTF-8";
    private JobExecutionContext executionContext = null;
    protected String _dataPath = null;
    protected Properties properties = null;
    private Dgn7fileReader reader = null;
    private String filename = null;
    public AbstractDgnFileJobContext(String dataPath)
    {
        _dataPath = dataPath;
    }
    public String getDataPath()
    {
        return _dataPath;
    }
    public JobExecutionContext getExecutionContext()
    {
        return executionContext;
    }
    public void setExecutionContext(JobExecutionContext context)
    {
        executionContext = context;
    }
    public abstract void startTransaction();
    public abstract void commitTransaction();
    public abstract void rollbackTransaction();
    public abstract String getDataOutPath();
    public Dgn7fileReader getReader()
    {
        return this.reader;
    }
    public void setReader(Dgn7fileReader reader)
    {
        this.reader = reader;
    }
    public String getFilename()
    {
        return filename;
    }
    public void setFilename(String filename)
    {
        this.filename = filename;
    }
}
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleDatabaseJob.java
@@ -155,4 +155,53 @@
        return raw;
    }
    public String getDataPath()
    {
        return _dataPath;
    }
    public String getFilterPath()
    {
        return _filterPath;
    }
    public String getOracleHost()
    {
        return _oracleHost;
    }
    public String getOracleInstance()
    {
        return _oracleInstance;
    }
    public String getOraclePort()
    {
        return _oraclePort;
    }
    public String getUsername()
    {
        return _username;
    }
    public String getPassword()
    {
        return _password;
    }
    public ArrayList<String> getOriginSchema()
    {
        return _orgSchema;
    }
    public boolean isTestMode()
    {
        return _testMode;
    }
    public int getTestCount()
    {
        return _testCount;
    }
}
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/AbstractOracleJobContext.java
@@ -206,6 +206,7 @@
    protected static final String STMT_CLEARCYCLEBIN = "PURGE RECYCLEBIN";
    protected static final String SMTM_GRANTOBJECTTYPE = "GRANT EXECUTE ANY TYPE TO \"" + UDT_SCHEMA + "\"";
    protected static final long TIMEOUT = Long.MAX_VALUE;
    /**
     * Encoding of URL path.
     */
@@ -286,6 +287,26 @@
        _oraclePort = oraclePort;
    }
    public String getDataPath()
    {
        return _dataPath;
    }
    public String getOracleHost()
    {
        return _oracleHost;
    }
    public String getOracleInstance()
    {
        return _oracleInstance;
    }
    public String getOraclePort()
    {
        return _oraclePort;
    }
    public abstract void startTransaction();
    public abstract void commitTransaction();
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/GeneralDgnConvertJobContext.java
New file
@@ -0,0 +1,43 @@
package com.ximple.eofms.jobs;
import java.io.File;
public class GeneralDgnConvertJobContext extends AbstractDgnFileJobContext
{
    private final static String SHPOUTPATH = "shpout";
    private String dataOut = null;
    public GeneralDgnConvertJobContext(String dataPath)
    {
        super(dataPath);
    }
    public void startTransaction()
    {
    }
    public void commitTransaction()
    {
    }
    public void rollbackTransaction()
    {
    }
    public String getDataOutPath()
    {
        if (dataOut == null)
        {
            File outPath = new File(getDataPath(), SHPOUTPATH);
            if (!outPath.exists())
            {
                outPath.mkdir();
            } else if (!outPath.isDirectory())
            {
                outPath.mkdir();
            }
            dataOut = getDataPath() + SHPOUTPATH;
        }
        return dataOut;
    }
}
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/IndexDgnConvertJobContext.java
New file
@@ -0,0 +1,269 @@
package com.ximple.eofms.jobs;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
import java.net.MalformedURLException;
import org.geotools.feature.Feature;
import org.geotools.feature.FeatureType;
import org.geotools.feature.SchemaException;
import org.geotools.feature.FeatureTypeBuilder;
import org.geotools.feature.AttributeTypeFactory;
import org.geotools.feature.FeatureTypeFactory;
import org.geotools.feature.IllegalAttributeException;
import org.geotools.feature.SimpleFeature;
import org.geotools.data.FeatureWriter;
import org.geotools.data.Transaction;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.apache.commons.transaction.memory.PessimisticMapWrapper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Coordinate;
import com.ximple.io.dgn7.Dgn7fileReader;
import com.ximple.io.dgn7.Element;
import com.ximple.io.dgn7.FrammeAttributeData;
import com.ximple.io.dgn7.TextElement;
import com.ximple.io.dgn7.ShapeElement;
import com.ximple.io.dgn7.ComplexShapeElement;
import com.ximple.io.dgn7.UserAttributeData;
import com.ximple.eofms.filter.AbstractFLinkageDispatchableFilter;
import com.ximple.eofms.util.TPCLIDConverter;
import com.ximple.eofms.util.DefaultColorTable;
import com.ximple.eofms.util.StringUtils;
public class IndexDgnConvertJobContext extends AbstractDgnFileJobContext
{
    static Log logger = LogFactory.getLog(IndexDgnConvertJobContext.class);
    static GeometryFactory geometryFactory = new GeometryFactory();
    private final static String SHPOUTPATH = "shpout";
    private String dataOut = null;
    private HashMap featuresContext = new HashMap();
    private HashMap featuresWriterContext = new HashMap();
    private PessimisticMapWrapper txFeaturesContext;
    private FeatureTypeBuilder typeBuilder = null;
    private FeatureType featureType = null;
    public IndexDgnConvertJobContext(String dataPath)
    {
        super(dataPath);
    }
    public void putFeatureCollection(Element element) throws IllegalAttributeException, SchemaException
    {
        if (!(element instanceof TextElement))
        {
            return;
        }
        Feature feature = createFeature((TextElement) element);
        if (feature == null)
        {
            logger.info("cannot craete feature." + element.toString() + "'" +
                    ((TextElement) element).getText() + "'");
            return;
        }
        if (!txFeaturesContext.containsKey(feature.getFeatureType()))
        {
            txFeaturesContext.put(feature.getFeatureType(), new ArrayList());
        }
        ArrayList arrayList = (ArrayList) txFeaturesContext.get(feature.getFeatureType());
        arrayList.add(feature);
    }
    public void startTransaction()
    {
    }
    public void commitTransaction()
    {
        if (!txFeaturesContext.isEmpty())
        {
             logger.debug("Transaction size = " + txFeaturesContext.size());
            //txFeaturesContext.commitTransaction();
         } else
         {
             logger.debug("Transaction is empty.");
         }
         if (!featuresContext.isEmpty())
         {
             updateDataStore();
         }
    }
    public void rollbackTransaction()
    {
        //txFeaturesContext.rollbackTransaction();
         if (!featuresContext.isEmpty())
         {
             updateDataStore();
         }
    }
    private void updateDataStore()
    {
        Iterator it = featuresContext.keySet().iterator();
        try
        {
            while (it.hasNext())
            {
                FeatureType featureType = (FeatureType) it.next();
                File sfile = new File(getDataOutPath() + "\\" + featureType.getTypeName());
                logger.debug("Begin Save shapefile:" + sfile.toURI());
                FeatureWriter writer = null;
                if(featuresWriterContext.containsKey(featureType.getTypeName()))
                {
                    writer = (FeatureWriter) featuresWriterContext.get(featureType.getTypeName()) ;
                }
                else
                {
                  ShapefileDataStore shapefileDataStore = new ShapefileDataStore(sfile.toURI().toURL());
                  shapefileDataStore.createSchema(featureType);
                  writer = shapefileDataStore.getFeatureWriter(featureType.getTypeName(), Transaction.AUTO_COMMIT);
                  if(this.featuresWriterContext == null)
                  {
                     this.featuresWriterContext =  new HashMap();
                  }
                  featuresWriterContext.put(featureType.getTypeName() , writer);
                }
                ArrayList features = (ArrayList) featuresContext.get(featureType);
                Iterator itFeature = features.iterator();
                while (itFeature.hasNext())
                {
                    Feature feature = (Feature) itFeature.next();
                    ((SimpleFeature) writer.next()).setAttributes(feature.getAttributes(null));
                }
                //writer.close();
                logger.debug("End Save shapefile:" + sfile.toURI());
            }
            featuresContext.clear();
        } catch (MalformedURLException e)
        {
            logger.error(e.getMessage(), e);
        } catch (IllegalAttributeException e)
        {
            logger.error(e.getMessage(), e);
        } catch (IOException e)
        {
            logger.error(e.getMessage(), e);
        }
    }
    public String getDataOutPath()
    {
        if (dataOut == null)
        {
            File outPath = new File(getDataPath(), SHPOUTPATH);
            if (!outPath.exists())
            {
                outPath.mkdir();
            } else if (!outPath.isDirectory())
            {
                outPath.mkdir();
            }
            dataOut = getDataPath() + SHPOUTPATH;
        }
        return dataOut;
    }
    public FeatureType createFeatureElement(String featureName) throws SchemaException
    {
        if (typeBuilder == null)
        {
            typeBuilder = FeatureTypeBuilder.newInstance(featureName);
            typeBuilder.addType(AttributeTypeFactory.newAttributeType("GEOM", Geometry.class));
            typeBuilder.addType(AttributeTypeFactory.newAttributeType("X1", Double.class));
            typeBuilder.addType(AttributeTypeFactory.newAttributeType("Y1", Double.class));
            typeBuilder.addType(AttributeTypeFactory.newAttributeType("X2", Double.class));
            typeBuilder.addType(AttributeTypeFactory.newAttributeType("Y2", Double.class));
            typeBuilder.addType(AttributeTypeFactory.newAttributeType("TPCID", String.class));
            typeBuilder.addType(AttributeTypeFactory.newAttributeType("SYMCOLOR", String.class));
            typeBuilder.addType(AttributeTypeFactory.newAttributeType("SYMWEIGHT", Integer.class));
            typeBuilder.addType(AttributeTypeFactory.newAttributeType("SYMSTYLE", Integer.class));
        }
        return typeBuilder.getFeatureType();
    }
    public Feature createFeature(FeatureType featureType, Element element) throws IllegalAttributeException
    {
        DefaultColorTable colorTable = (DefaultColorTable) DefaultColorTable.getInstance();
        if (element instanceof TextElement)
        {
            TextElement textElm = (TextElement) element;
            String tpclid = textElm.getText();
            Envelope extent = TPCLIDConverter.convertTpclIdToEnvelope(tpclid);
            Geometry geom = geometryFactory.createLinearRing(new Coordinate[]
            {
                    new Coordinate(extent.getMinX(), extent.getMinY()),
                    new Coordinate(extent.getMaxX(), extent.getMinY()),
                    new Coordinate(extent.getMaxX(), extent.getMaxY()),
                    new Coordinate(extent.getMinX(), extent.getMaxY()),
                    new Coordinate(extent.getMinX(), extent.getMinY()),
            });
            TextElement textElement = (TextElement) element;
            Feature feature = featureType.create(new Object[]{
                    geom,
                    extent.getMinX(),
                    extent.getMinY(),
                    extent.getMaxX(),
                    extent.getMaxY(),
                    tpclid,
                    colorTable.getColorCode(textElement.getColorIndex()),
                    textElement.getWeight(),
                    textElement.getLineStyle()
            });
            return feature;
        }
        return null;
    }
    private Feature createFeature(TextElement element) throws SchemaException, IllegalAttributeException
    {
        if (featureType == null)
        {
            String dgnname = getFilename().toLowerCase();
            int i = dgnname.lastIndexOf(".");
            if (i != -1)
            {
                dgnname = dgnname.substring(0, i);
            }
            featureType = createFeatureElement(dgnname);
        }
        return createFeature(featureType, element);
    }
    protected FrammeAttributeData getFeatureLinkage(Element element)
    {
        if (!element.hasUserAttributeData())
            return null;
        List<UserAttributeData> usrDatas = element.getUserAttributeData();
        for (UserAttributeData anUsrData : usrDatas)
        {
            if (anUsrData instanceof FrammeAttributeData)
            {
                return (FrammeAttributeData) anUsrData;
            }
        }
        return null;
    }
}
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertDgn2ShpJob.java
@@ -1,14 +1,21 @@
package com.ximple.eofms.jobs;
import java.io.IOException;
import java.io.File;
import java.io.FilenameFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.Date;
import java.util.List;
import java.util.Iterator;
import org.apache.commons.collections.OrderedMap;
import org.apache.commons.collections.OrderedMapIterator;
@@ -18,8 +25,11 @@
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.geotools.feature.IllegalAttributeException;
import org.geotools.feature.SchemaException;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Envelope;
import oracle.jdbc.OracleConnection;
import oracle.jdbc.OracleResultSet;
@@ -28,11 +38,21 @@
import com.ximple.eofms.util.BinConverter;
import com.ximple.eofms.util.ByteArrayCompressor;
import com.ximple.eofms.util.TPCLIDConverter;
import com.ximple.eofms.util.StringUtils;
import com.ximple.io.dgn7.ComplexElement;
import com.ximple.io.dgn7.Dgn7fileException;
import com.ximple.io.dgn7.Element;
import com.ximple.io.dgn7.ElementType;
import com.ximple.io.dgn7.IElementHandler;
import com.ximple.io.dgn7.Dgn7fileReader;
import com.ximple.io.dgn7.Lock;
import com.ximple.io.dgn7.ComplexChainElement;
import com.ximple.io.dgn7.ComplexShapeElement;
import com.ximple.io.dgn7.TextNodeElement;
import com.ximple.io.dgn7.TextElement;
import com.ximple.io.dgn7.UserAttributeData;
import com.ximple.io.dgn7.FrammeAttributeData;
import com.ximple.util.PrintfFormat;
/**
@@ -104,6 +124,9 @@
                //close all open filewriter instance
                jobContext.closeFeatureWrite();
            }
            convertIndexDesignFile(context);
            convertOtherDesignFile(context);
        } catch (SQLException e)
        {
            logger.warn(e.getMessage(), e);
@@ -115,7 +138,11 @@
        }
    }
    //Connectivity½Æ»s¤@­Óª©¥»¡A¦b¬d¸ß¹q¬y¤è¦V®É¥Î¨Ó¤ñ¹ïOMS¸ê®Æ®wªº¹q¾¹³s±µ©Ê(Connectivity)
    /**
     * Connectivity½Æ»s¤@­Óª©¥»¡A¦b¬d¸ß¹q¬y¤è¦V®É¥Î¨Ó¤ñ¹ïOMS¸ê®Æ®wªº¹q¾¹³s±µ©Ê(Connectivity)
     * @param jobContext
     * @throws SQLException
     */
    private void copyConnectivity(OracleConvertJobContext jobContext) throws SQLException
    {
        OracleConnection connection = jobContext.getOracleConnection();
@@ -421,4 +448,268 @@
        return dgnElement;
    }
    /**
     * °õ¦æÂà´«¯Á¤Þ¹ÏÀɪº¤u§@
     * @param context ¤u§@°õ¦æÀô¹Ò
     */
    private void convertIndexDesignFile(JobExecutionContext context) throws JobExecutionException
    {
        File indexDir = new File(getDataPath(), "index");
        if (!indexDir.exists())
        {
            logger.info("index dir=" + indexDir + " not exist.");
            return;
        }
        if (!indexDir.isDirectory())
        {
            logger.info("index dir=" + indexDir + " is not a directory.");
        }
        File[] dgnFiles = indexDir.listFiles(new FilenameFilter()
        {
            public boolean accept(File dir, String name)
            {
                return name.toLowerCase().endsWith(".dgn");
            }
        });
        for (File dgnFile : dgnFiles)
        {
            IndexDgnConvertJobContext convertContext = new IndexDgnConvertJobContext(getDataPath());
            try
            {
                convertContext.setExecutionContext(context);
                String dgnPaths[] = StringUtils.splitToArray(dgnFile.toString(), File.pathSeparator);
                convertContext.setFilename(dgnPaths[dgnPaths.length - 1]);
                FileInputStream fs = new FileInputStream(dgnFile);
                FileChannel fc = fs.getChannel();
                Dgn7fileReader reader = new Dgn7fileReader(fc, new Lock());
                convertContext.setReader(reader);
                scanIndexDgnElement(convertContext);
                convertContext.commitTransaction();
            } catch (FileNotFoundException e)
            {
                convertContext.rollbackTransaction();
                logger.warn(e.getMessage(), e);
                throw new JobExecutionException(e.getMessage(), e);
            } catch (Dgn7fileException e)
            {
                convertContext.rollbackTransaction();
                logger.warn(e.getMessage(), e);
                throw new JobExecutionException(e.getMessage(), e);
            } catch (IOException e)
            {
                convertContext.rollbackTransaction();
                logger.warn(e.getMessage(), e);
                throw new JobExecutionException(e.getMessage(), e);
            } catch (IllegalAttributeException e)
            {
                convertContext.rollbackTransaction();
                logger.warn(e.getMessage(), e);
                throw new JobExecutionException(e.getMessage(), e);
            } catch (SchemaException e)
            {
                convertContext.rollbackTransaction();
                logger.warn(e.getMessage(), e);
                throw new JobExecutionException(e.getMessage(), e);
            }
        }
    }
    protected void scanIndexDgnElement(IndexDgnConvertJobContext convertContext)
            throws Dgn7fileException, IOException, IllegalAttributeException, SchemaException
    {
        Dgn7fileReader reader = convertContext.getReader();
        int count = 0;
        Element lastComplex = null;
        while (reader.hasNext())
        {
            Dgn7fileReader.Record record = reader.nextElement();
            if (record.element() != null)
            {
                Element element = (Element) record.element();
                ElementType type = element.getElementType();
                if ((!type.isComplexElement()) && (!element.isComponentElement()))
                {
                    lastComplex = null;
                    processElement(element, convertContext);
                } else if (element.isComponentElement())
                {
                    if (lastComplex != null)
                    {
                        ((ComplexElement) lastComplex).add(element);
                    }
                } else if (type.isComplexElement())
                {
                    if (lastComplex == null)
                    {
                        lastComplex = element;
                    } else
                    {
                        processElement(element, convertContext);
                        lastComplex = element;
                    }
                }
            }
            count++;
        }
        logger.debug("ElementRecord Count=" + count);
    }
    private void processElement(Element element, IndexDgnConvertJobContext convertContext) throws IllegalAttributeException, SchemaException
    {
        if (element instanceof TextElement)
        {
            convertContext.putFeatureCollection(element);
        }
    }
    /**
     * °õ¦æÂà´«¨ä¥L³]­p¹ÏÀɪº¤u§@
     * @param context
     */
    private void convertOtherDesignFile(JobExecutionContext context)
    {
        File otherDir = new File(getDataPath(), "other");
        if (!otherDir.exists())
        {
            logger.info("index dir=" + otherDir + " not exist.");
            return;
        }
        if (!otherDir.isDirectory())
        {
            logger.info("index dir=" + otherDir + " is not a directory.");
        }
        File[] dgnFiles = otherDir.listFiles(new FilenameFilter()
        {
            public boolean accept(File dir, String name)
            {
                return name.toLowerCase().endsWith(".dgn");
            }
        });
        for (File dgnFile : dgnFiles)
        {
            GeneralDgnConvertJobContext convertContext = new GeneralDgnConvertJobContext(getDataPath());
            convertContext.setExecutionContext(context);
        }
    }
    public void scanOtherDgnElement(GeneralDgnConvertJobContext convertContext) throws Dgn7fileException, IOException
    {
        Dgn7fileReader reader = convertContext.getReader();
        int count = 0;
        Element lastComplex = null;
        while (reader.hasNext())
        {
            Dgn7fileReader.Record record = reader.nextElement();
            if (record.element() != null)
            {
                Element element = (Element) record.element();
                ElementType type = element.getElementType();
                if ((!type.isComplexElement()) && (!element.isComponentElement()))
                {
                    if (lastComplex != null)
                    {
                        // @todo add process in here
                        lastComplex = null;
                    }
                    // @todo add process in here
                } else if (element.isComponentElement())
                {
                    if (lastComplex != null)
                    {
                        ((ComplexElement) lastComplex).add(element);
                    }
                } else if (type.isComplexElement())
                {
                    if (lastComplex == null)
                    {
                        lastComplex = element;
                    } else
                    {
                        // @todo add process in here
                        lastComplex = element;
                    }
                }
                if (element.getElementType().isComplexElement())
                {
                    if (element instanceof ComplexChainElement)
                    {
                        ComplexChainElement complexChain = (ComplexChainElement) element;
                        int size = complexChain.size();
                        for (Object aComplexChain : complexChain)
                        {
                            Element subElement = (Element) aComplexChain;
                            subElement.getType();
                        }
                    }
                    if (element instanceof ComplexShapeElement)
                    {
                        ComplexShapeElement complexShape = (ComplexShapeElement) element;
                    }
                    if (element instanceof TextNodeElement)
                    {
                        TextNodeElement textNode = (TextNodeElement) element;
                        int size = textNode.size();
                        for (int i = 0; i < size; i++)
                        {
                            Element subElement = (Element) textNode.get(i);
                            subElement.getElementType();
                        }
                    }
                } else
                {
                    boolean hasLinkage = false;
                    if (element instanceof TextElement)
                    {
                        TextElement textElm = (TextElement) element;
                        List<UserAttributeData> usrData = textElm.getUserAttributeData();
                        Iterator<UserAttributeData> it = usrData.iterator();
                        while (it.hasNext())
                        {
                            UserAttributeData attr = it.next();
                            if (attr instanceof FrammeAttributeData)
                            {
                                hasLinkage = true;
                                System.out.println("------------------------------------------");
                                System.out.println("FSC=" + ((FrammeAttributeData) attr).getFsc() + ":" +
                                        ((FrammeAttributeData) attr).getUfid());
                            }
                        }
                        if (hasLinkage)
                        {
                            System.out.println("Text.Font=" + textElm.getFontIndex());
                            System.out.println("Text.Just=" + textElm.getJustification());
                            System.out.println("usrData.len=" + usrData.size());
                            System.out.println("text=" + textElm.getText());
                            System.out.println("Origin=" + textElm.getOrigin());
                            System.out.println("UserOrigin=" + textElm.getUserOrigin());
                        }
                    }
                }
            }
            count++;
        }
        logger.info("ElementRecord Count=" + count);
    }
}
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/OracleConvertJobContext.java
@@ -42,6 +42,8 @@
    static Log logger = LogFactory.getLog(OracleConvertJobContext.class);
    static final LoggerFacade sLogger = new CommonsLoggingLogger(logger);
    private static final String SHPOUTPATH = "shpout";
    static
    {
        try
@@ -62,6 +64,8 @@
    private PessimisticMapWrapper txFeaturesContext;
    private JobExecutionContext executionContext;
    private String dataOut = null;
    public OracleConvertJobContext(String filterConfig)
    {
@@ -116,7 +120,7 @@
    public void putFeatureCollection(Element element)
    {
        //§PÂ_¬O§_²Å©M±ø¥ó
        // §PÂ_¬O§_²Å©M±ø¥ó
        Feature feature = elementDispatcher.execute(element);
        if (feature == null)
        {
@@ -170,15 +174,14 @@
    private void updateDataStore()
    {
        // todo:
        Iterator it = featuresContext.keySet().iterator();
        Iterator it = featuresContext.keySet().iterator();
        try
        {
            while (it.hasNext())
            {
                FeatureType featureType = (FeatureType) it.next();
                File sfile = new File(_dataPath + "\\" + featureType.getTypeName());
                File sfile = new File(getDataOutPath() + "\\" + featureType.getTypeName());
                logger.debug("Begin Save shapefile:" + sfile.toURI());
                FeatureWriter writer = null;
@@ -232,6 +235,10 @@
        executionContext = context;
    }
    /**
     * Ãö³¬³]³Æ¼g¤J¾¹
     * @throws IOException IOµo¥Í¿ù»~
     */
    public void closeFeatureWrite() throws IOException {
       Iterator iter =   this.featuresWriterContext.values().iterator();
@@ -243,4 +250,25 @@
        this.featuresWriterContext = null;
    }
    /**
     * ¨ú±o¸ê®Æ¿é¥X¸ô®|
     * @return ¸ô®|ªº¦r¦ê
     */
    public String getDataOutPath()
    {
        if (dataOut == null)
        {
            File outPath = new File(getDataPath(), SHPOUTPATH);
            if (!outPath.exists())
            {
                outPath.mkdir();
            } else if (!outPath.isDirectory())
            {
                outPath.mkdir();
            }
            dataOut = getDataPath() + SHPOUTPATH;
        }
        return dataOut;
    }
}
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/Base64.java
New file
@@ -0,0 +1,551 @@
package com.ximple.eofms.util;
import java.util.Arrays;
public class Base64
{
    private static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
    private static final int[] IA = new int[256];
    static
    {
        Arrays.fill(IA, -1);
        for (int i = 0, iS = CA.length; i < iS; i++)
            IA[CA[i]] = i;
        IA['='] = 0;
    }
    // ****************************************************************************************
    // *  char[] version
    // ****************************************************************************************
    /**
     * Encodes a raw byte array into a BASE64 <code>char[]</code> representation i accordance with RFC 2045.
     *
     * @param sArr    The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
     * @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
     *                No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
     *                little faster.
     * @return A BASE64 encoded array. Never <code>null</code>.
     */
    public static char[] encodeToChar(byte[] sArr, boolean lineSep)
    {
        // Check special case
        int sLen = sArr != null ? sArr.length : 0;
        if (sLen == 0)
            return new char[0];
        int eLen = (sLen / 3) * 3;              // Length of even 24-bits.
        int cCnt = ((sLen - 1) / 3 + 1) << 2;   // Returned character count
        int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
        char[] dArr = new char[dLen];
        // Encode even 24-bits
        for (int s = 0, d = 0, cc = 0; s < eLen;)
        {
            // Copy next three bytes into lower 24 bits of int, paying attension to sign.
            int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
            // Encode the int into four chars
            dArr[d++] = CA[(i >>> 18) & 0x3f];
            dArr[d++] = CA[(i >>> 12) & 0x3f];
            dArr[d++] = CA[(i >>> 6) & 0x3f];
            dArr[d++] = CA[i & 0x3f];
            // Add optional line separator
            if (lineSep && ++cc == 19 && d < dLen - 2)
            {
                dArr[d++] = '\r';
                dArr[d++] = '\n';
                cc = 0;
            }
        }
        // Pad and encode last bits if source isn't even 24 bits.
        int left = sLen - eLen; // 0 - 2.
        if (left > 0)
        {
            // Prepare the int
            int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
            // Set last four chars
            dArr[dLen - 4] = CA[i >> 12];
            dArr[dLen - 3] = CA[(i >>> 6) & 0x3f];
            dArr[dLen - 2] = left == 2 ? CA[i & 0x3f] : '=';
            dArr[dLen - 1] = '=';
        }
        return dArr;
    }
    /**
     * Decodes a BASE64 encoded char array. All illegal characters will be ignored and can handle both arrays with
     * and without line separators.
     *
     * @param sArr The source array. <code>null</code> or length 0 will return an empty array.
     * @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
     *         (including '=') isn't divideable by 4.  (I.e. definitely corrupted).
     */
    public static byte[] decode(char[] sArr)
    {
        // Check special case
        int sLen = sArr != null ? sArr.length : 0;
        if (sLen == 0)
            return new byte[0];
        // Count illegal characters (including '\r', '\n') to know what size the returned array will be,
        // so we don't have to reallocate & copy it later.
        int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
        for (int i = 0; i < sLen; i++)  // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
            if (IA[sArr[i]] < 0)
                sepCnt++;
        // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
        if ((sLen - sepCnt) % 4 != 0)
            return null;
        int pad = 0;
        for (int i = sLen; i > 1 && IA[sArr[--i]] <= 0;)
            if (sArr[i] == '=')
                pad++;
        int len = ((sLen - sepCnt) * 6 >> 3) - pad;
        byte[] dArr = new byte[len];       // Preallocate byte[] of exact length
        for (int s = 0, d = 0; d < len;)
        {
            // Assemble three bytes into an int from four "valid" characters.
            int i = 0;
            for (int j = 0; j < 4; j++)
            {   // j only increased if a valid char was found.
                int c = IA[sArr[s++]];
                if (c >= 0)
                    i |= c << (18 - j * 6);
                else
                    j--;
            }
            // Add the bytes
            dArr[d++] = (byte) (i >> 16);
            if (d < len)
            {
                dArr[d++] = (byte) (i >> 8);
                if (d < len)
                    dArr[d++] = (byte) i;
            }
        }
        return dArr;
    }
    /**
     * Decodes a BASE64 encoded char array that is known to be resonably well formatted. The method is about twice as
     * fast as {@link #decode(char[])}. The preconditions are:<br>
     * + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
     * + Line separator must be "\r\n", as specified in RFC 2045
     * + The array must not contain illegal characters within the encoded string<br>
     * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
     *
     * @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
     * @return The decoded array of bytes. May be of length 0.
     */
    public byte[] decodeFast(char[] sArr)
    {
        // Check special case
        int sLen = sArr.length;
        if (sLen == 0)
            return new byte[0];
        int sIx = 0, eIx = sLen - 1;    // Start and end index after trimming.
        // Trim illegal chars from start
        while (sIx < eIx && IA[sArr[sIx]] < 0)
            sIx++;
        // Trim illegal chars from end
        while (eIx > 0 && IA[sArr[eIx]] < 0)
            eIx--;
        // get the padding count (=) (0, 1 or 2)
        int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0;  // Count '=' at end.
        int cCnt = eIx - sIx + 1;   // Content count including possible separators
        int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
        int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
        byte[] dArr = new byte[len];       // Preallocate byte[] of exact length
        // Decode all but the last 0 - 2 bytes.
        int d = 0;
        for (int cc = 0, eLen = (len / 3) * 3; d < eLen;)
        {
            // Assemble three bytes into an int from four "valid" characters.
            int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
            // Add the bytes
            dArr[d++] = (byte) (i >> 16);
            dArr[d++] = (byte) (i >> 8);
            dArr[d++] = (byte) i;
            // If line separator, jump over it.
            if (sepCnt > 0 && ++cc == 19)
            {
                sIx += 2;
                cc = 0;
            }
        }
        if (d < len)
        {
            // Decode last 1-3 bytes (incl '=') into 1-3 bytes
            int i = 0;
            for (int j = 0; sIx <= eIx - pad; j++)
                i |= IA[sArr[sIx++]] << (18 - j * 6);
            for (int r = 16; d < len; r -= 8)
                dArr[d++] = (byte) (i >> r);
        }
        return dArr;
    }
    // ****************************************************************************************
    // *  byte[] version
    // ****************************************************************************************
    /**
     * Encodes a raw byte array into a BASE64 <code>byte[]</code> representation i accordance with RFC 2045.
     *
     * @param sArr    The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
     * @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
     *                No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
     *                little faster.
     * @return A BASE64 encoded array. Never <code>null</code>.
     */
    public static byte[] encodeToByte(byte[] sArr, boolean lineSep)
    {
        // Check special case
        int sLen = sArr != null ? sArr.length : 0;
        if (sLen == 0)
            return new byte[0];
        int eLen = (sLen / 3) * 3;                              // Length of even 24-bits.
        int cCnt = ((sLen - 1) / 3 + 1) << 2;                   // Returned character count
        int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
        byte[] dArr = new byte[dLen];
        // Encode even 24-bits
        for (int s = 0, d = 0, cc = 0; s < eLen;)
        {
            // Copy next three bytes into lower 24 bits of int, paying attension to sign.
            int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
            // Encode the int into four chars
            dArr[d++] = (byte) CA[(i >>> 18) & 0x3f];
            dArr[d++] = (byte) CA[(i >>> 12) & 0x3f];
            dArr[d++] = (byte) CA[(i >>> 6) & 0x3f];
            dArr[d++] = (byte) CA[i & 0x3f];
            // Add optional line separator
            if (lineSep && ++cc == 19 && d < dLen - 2)
            {
                dArr[d++] = '\r';
                dArr[d++] = '\n';
                cc = 0;
            }
        }
        // Pad and encode last bits if source isn't an even 24 bits.
        int left = sLen - eLen; // 0 - 2.
        if (left > 0)
        {
            // Prepare the int
            int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
            // Set last four chars
            dArr[dLen - 4] = (byte) CA[i >> 12];
            dArr[dLen - 3] = (byte) CA[(i >>> 6) & 0x3f];
            dArr[dLen - 2] = left == 2 ? (byte) CA[i & 0x3f] : (byte) '=';
            dArr[dLen - 1] = '=';
        }
        return dArr;
    }
    /**
     * Decodes a BASE64 encoded byte array. All illegal characters will be ignored and can handle both arrays with
     * and without line separators.
     *
     * @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
     * @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
     *         (including '=') isn't divideable by 4. (I.e. definitely corrupted).
     */
    public static byte[] decode(byte[] sArr)
    {
        // Check special case
        int sLen = sArr.length;
        // Count illegal characters (including '\r', '\n') to know what size the returned array will be,
        // so we don't have to reallocate & copy it later.
        int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
        for (int i = 0; i < sLen; i++)      // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
            if (IA[sArr[i] & 0xff] < 0)
                sepCnt++;
        // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
        if ((sLen - sepCnt) % 4 != 0)
            return null;
        int pad = 0;
        for (int i = sLen; i > 1 && IA[sArr[--i] & 0xff] <= 0;)
            if (sArr[i] == '=')
                pad++;
        int len = ((sLen - sepCnt) * 6 >> 3) - pad;
        byte[] dArr = new byte[len];       // Preallocate byte[] of exact length
        for (int s = 0, d = 0; d < len;)
        {
            // Assemble three bytes into an int from four "valid" characters.
            int i = 0;
            for (int j = 0; j < 4; j++)
            {   // j only increased if a valid char was found.
                int c = IA[sArr[s++] & 0xff];
                if (c >= 0)
                    i |= c << (18 - j * 6);
                else
                    j--;
            }
            // Add the bytes
            dArr[d++] = (byte) (i >> 16);
            if (d < len)
            {
                dArr[d++] = (byte) (i >> 8);
                if (d < len)
                    dArr[d++] = (byte) i;
            }
        }
        return dArr;
    }
    /**
     * Decodes a BASE64 encoded byte array that is known to be resonably well formatted. The method is about twice as
     * fast as {@link #decode(byte[])}. The preconditions are:<br>
     * + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
     * + Line separator must be "\r\n", as specified in RFC 2045
     * + The array must not contain illegal characters within the encoded string<br>
     * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
     *
     * @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
     * @return The decoded array of bytes. May be of length 0.
     */
    public static byte[] decodeFast(byte[] sArr)
    {
        // Check special case
        int sLen = sArr.length;
        if (sLen == 0)
            return new byte[0];
        int sIx = 0, eIx = sLen - 1;    // Start and end index after trimming.
        // Trim illegal chars from start
        while (sIx < eIx && IA[sArr[sIx] & 0xff] < 0)
            sIx++;
        // Trim illegal chars from end
        while (eIx > 0 && IA[sArr[eIx] & 0xff] < 0)
            eIx--;
        // get the padding count (=) (0, 1 or 2)
        int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0;  // Count '=' at end.
        int cCnt = eIx - sIx + 1;   // Content count including possible separators
        int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
        int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
        byte[] dArr = new byte[len];       // Preallocate byte[] of exact length
        // Decode all but the last 0 - 2 bytes.
        int d = 0;
        for (int cc = 0, eLen = (len / 3) * 3; d < eLen;)
        {
            // Assemble three bytes into an int from four "valid" characters.
            int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
            // Add the bytes
            dArr[d++] = (byte) (i >> 16);
            dArr[d++] = (byte) (i >> 8);
            dArr[d++] = (byte) i;
            // If line separator, jump over it.
            if (sepCnt > 0 && ++cc == 19)
            {
                sIx += 2;
                cc = 0;
            }
        }
        if (d < len)
        {
            // Decode last 1-3 bytes (incl '=') into 1-3 bytes
            int i = 0;
            for (int j = 0; sIx <= eIx - pad; j++)
                i |= IA[sArr[sIx++]] << (18 - j * 6);
            for (int r = 16; d < len; r -= 8)
                dArr[d++] = (byte) (i >> r);
        }
        return dArr;
    }
    // ****************************************************************************************
    // * String version
    // ****************************************************************************************
    /**
     * Encodes a raw byte array into a BASE64 <code>String</code> representation i accordance with RFC 2045.
     *
     * @param sArr    The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
     * @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
     *                No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
     *                little faster.
     * @return A BASE64 encoded array. Never <code>null</code>.
     */
    public static String encodeToString(byte[] sArr, boolean lineSep)
    {
        // Reuse char[] since we can't create a String incrementally anyway and StringBuffer/Builder would be slower.
        return new String(encodeToChar(sArr, lineSep));
    }
    /**
     * Decodes a BASE64 encoded <code>String</code>. All illegal characters will be ignored and can handle both strings with
     * and without line separators.<br>
     * <b>Note!</b> It can be up to about 2x the speed to call <code>decode(str.toCharArray())</code> instead. That
     * will create a temporary array though. This version will use <code>str.charAt(i)</code> to iterate the string.
     *
     * @param str The source string. <code>null</code> or length 0 will return an empty array.
     * @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
     *         (including '=') isn't divideable by 4.  (I.e. definitely corrupted).
     */
    public static byte[] decode(String str)
    {
        // Check special case
        int sLen = str != null ? str.length() : 0;
        if (sLen == 0)
            return new byte[0];
        // Count illegal characters (including '\r', '\n') to know what size the returned array will be,
        // so we don't have to reallocate & copy it later.
        int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
        for (int i = 0; i < sLen; i++)  // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
            if (IA[str.charAt(i)] < 0)
                sepCnt++;
        // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
        if ((sLen - sepCnt) % 4 != 0)
            return null;
        // Count '=' at end
        int pad = 0;
        for (int i = sLen; i > 1 && IA[str.charAt(--i)] <= 0;)
            if (str.charAt(i) == '=')
                pad++;
        int len = ((sLen - sepCnt) * 6 >> 3) - pad;
        byte[] dArr = new byte[len];       // Preallocate byte[] of exact length
        for (int s = 0, d = 0; d < len;)
        {
            // Assemble three bytes into an int from four "valid" characters.
            int i = 0;
            for (int j = 0; j < 4; j++)
            {   // j only increased if a valid char was found.
                int c = IA[str.charAt(s++)];
                if (c >= 0)
                    i |= c << (18 - j * 6);
                else
                    j--;
            }
            // Add the bytes
            dArr[d++] = (byte) (i >> 16);
            if (d < len)
            {
                dArr[d++] = (byte) (i >> 8);
                if (d < len)
                    dArr[d++] = (byte) i;
            }
        }
        return dArr;
    }
    /**
     * Decodes a BASE64 encoded string that is known to be resonably well formatted. The method is about twice as
     * fast as {@link #decode(String)}. The preconditions are:<br>
     * + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
     * + Line separator must be "\r\n", as specified in RFC 2045
     * + The array must not contain illegal characters within the encoded string<br>
     * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
     *
     * @param s The source string. Length 0 will return an empty array. <code>null</code> will throw an exception.
     * @return The decoded array of bytes. May be of length 0.
     */
    public static byte[] decodeFast(String s)
    {
        // Check special case
        int sLen = s.length();
        if (sLen == 0)
            return new byte[0];
        int sIx = 0, eIx = sLen - 1;    // Start and end index after trimming.
        // Trim illegal chars from start
        while (sIx < eIx && IA[s.charAt(sIx) & 0xff] < 0)
            sIx++;
        // Trim illegal chars from end
        while (eIx > 0 && IA[s.charAt(eIx) & 0xff] < 0)
            eIx--;
        // get the padding count (=) (0, 1 or 2)
        int pad = s.charAt(eIx) == '=' ? (s.charAt(eIx - 1) == '=' ? 2 : 1) : 0;  // Count '=' at end.
        int cCnt = eIx - sIx + 1;   // Content count including possible separators
        int sepCnt = sLen > 76 ? (s.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0;
        int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
        byte[] dArr = new byte[len];       // Preallocate byte[] of exact length
        // Decode all but the last 0 - 2 bytes.
        int d = 0;
        for (int cc = 0, eLen = (len / 3) * 3; d < eLen;)
        {
            // Assemble three bytes into an int from four "valid" characters.
            int i = IA[s.charAt(sIx++)] << 18 | IA[s.charAt(sIx++)] << 12 | IA[s.charAt(sIx++)] << 6 | IA[s.charAt(sIx++)];
            // Add the bytes
            dArr[d++] = (byte) (i >> 16);
            dArr[d++] = (byte) (i >> 8);
            dArr[d++] = (byte) i;
            // If line separator, jump over it.
            if (sepCnt > 0 && ++cc == 19)
            {
                sIx += 2;
                cc = 0;
            }
        }
        if (d < len)
        {
            // Decode last 1-3 bytes (incl '=') into 1-3 bytes
            int i = 0;
            for (int j = 0; sIx <= eIx - pad; j++)
                i |= IA[s.charAt(sIx++)] << (18 - j * 6);
            for (int r = 16; d < len; r -= 8)
                dArr[d++] = (byte) (i >> r);
        }
        return dArr;
    }
}
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/StringUtils.java
New file
@@ -0,0 +1,2923 @@
package com.ximple.eofms.util;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Collection;
import java.util.Locale;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CharacterCodingException;
import java.nio.CharBuffer;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.lang.reflect.Array;
import java.text.BreakIterator;
public abstract class StringUtils
{
    public static String ENCODING_US_ASCII = "US-ASCII";
    public static String ENCODING_ISO_8859_1 = "ISO-8859-1";
    public static String ENCODING_ISO_8859_2 = "ISO-8859-2";
    public static String ENCODING_ISO_8859_5 = "ISO-8859-5";
    public static String ENCODING_UTF_8 = "UTF-8";
    public static String ENCODING_UTF_16BE = "UTF-16BE";
    public static String ENCODING_UTF_16LE = "UTF-16LE";
    public static String ENCODING_UTF_16 = "UTF-16";
    public static Charset CHARSET_US_ASCII = Charset.forName(StringUtils.ENCODING_US_ASCII);
    public static final Pattern BBCODE_COLOR = Pattern.compile("\\[color\\s*=\\s*([#\\w]*)\\s*\\]", Pattern.CASE_INSENSITIVE);
    public static final Pattern BBCODE_SIZE = Pattern.compile("\\[size\\s*=\\s*([+\\-]?[0-9]*)\\s*\\]", Pattern.CASE_INSENSITIVE);
    public static final Pattern BBCODE_URL_SHORT = Pattern.compile("\\[url\\]\\s*([^\\s]*)\\s*\\[\\/url\\]", Pattern.CASE_INSENSITIVE);
    public static final Pattern BBCODE_URL_LONG = Pattern.compile("\\[url=([^\\[]*)\\]([^\\[]*)\\[/url\\]", Pattern.CASE_INSENSITIVE);
    public static final Pattern BBCODE_IMG = Pattern.compile("\\[img\\]\\s*([^\\s]*)\\s*\\[\\/img\\]", Pattern.CASE_INSENSITIVE);
    public static final Pattern BBCODE_QUOTE_LONG = Pattern.compile("\\[quote=([^\\]]+\\]*)\\]", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
    public static final Pattern BBCODE_BAREURL = Pattern.compile("(?:[^\"'=>\\]]|^)((?:http|ftp)s?://(?:%[\\p{Digit}A-Fa-f][\\p{Digit}A-Fa-f]|[\\-_\\.!~*';\\|/?:@#&=\\+$,\\p{Alnum}])+)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
    private static final Map<Character, String> AGGRESSIVE_HTML_ENCODE_MAP = new HashMap<Character, String>();
    private static final Map<Character, String> DEFENSIVE_HTML_ENCODE_MAP = new HashMap<Character, String>();
    private static final Map<Character, String> XML_ENCODE_MAP = new HashMap<Character, String>();
    private static final Map<Character, String> STRING_ENCODE_MAP = new HashMap<Character, String>();
    private static final Map<Character, String> SQL_ENCODE_MAP = new HashMap<Character, String>();
    private static final Map<Character, String> LATEX_ENCODE_MAP = new HashMap<Character, String>();
    private static final Map<String, Character>        HTML_DECODE_MAP = new HashMap<String, Character>();
    private static final HtmlEncoderFallbackHandler HTML_ENCODER_FALLBACK = new HtmlEncoderFallbackHandler();
    static
    {
        // Html encoding mapping according to the HTML 4.0 spec
        // http://www.w3.org/TR/REC-html40/sgml/entities.html
        // Special characters for HTML
        AGGRESSIVE_HTML_ENCODE_MAP.put('\u0026',"&amp;");
        AGGRESSIVE_HTML_ENCODE_MAP.put('\u003C',"&lt;");
        AGGRESSIVE_HTML_ENCODE_MAP.put('\u003E',"&gt;");
        AGGRESSIVE_HTML_ENCODE_MAP.put('\u0022',"&quot;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u0152',"&OElig;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u0153',"&oelig;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u0160',"&Scaron;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u0161',"&scaron;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u0178',"&Yuml;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u02C6',"&circ;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u02DC',"&tilde;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2002',"&ensp;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2003',"&emsp;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2009',"&thinsp;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u200C',"&zwnj;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u200D',"&zwj;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u200E',"&lrm;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u200F',"&rlm;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2013',"&ndash;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2014',"&mdash;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2018',"&lsquo;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2019',"&rsquo;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u201A',"&sbquo;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u201C',"&ldquo;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u201D',"&rdquo;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u201E',"&bdquo;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2020',"&dagger;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2021',"&Dagger;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2030',"&permil;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2039',"&lsaquo;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u203A',"&rsaquo;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u20AC',"&euro;");
        // Character entity references for ISO 8859-1 characters
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00A0',"&nbsp;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00A1',"&iexcl;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00A2',"&cent;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00A3',"&pound;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00A4',"&curren;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00A5',"&yen;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00A6',"&brvbar;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00A7',"&sect;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00A8',"&uml;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00A9',"&copy;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00AA',"&ordf;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00AB',"&laquo;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00AC',"&not;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00AD',"&shy;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00AE',"&reg;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00AF',"&macr;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00B0',"&deg;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00B1',"&plusmn;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00B2',"&sup2;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00B3',"&sup3;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00B4',"&acute;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00B5',"&micro;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00B6',"&para;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00B7',"&middot;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00B8',"&cedil;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00B9',"&sup1;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00BA',"&ordm;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00BB',"&raquo;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00BC',"&frac14;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00BD',"&frac12;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00BE',"&frac34;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00BF',"&iquest;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00C0',"&Agrave;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00C1',"&Aacute;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00C2',"&Acirc;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00C3',"&Atilde;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00C4',"&Auml;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00C5',"&Aring;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00C6',"&AElig;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00C7',"&Ccedil;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00C8',"&Egrave;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00C9',"&Eacute;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00CA',"&Ecirc;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00CB',"&Euml;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00CC',"&Igrave;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00CD',"&Iacute;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00CE',"&Icirc;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00CF',"&Iuml;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00D0',"&ETH;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00D1',"&Ntilde;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00D2',"&Ograve;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00D3',"&Oacute;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00D4',"&Ocirc;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00D5',"&Otilde;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00D6',"&Ouml;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00D7',"&times;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00D8',"&Oslash;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00D9',"&Ugrave;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00DA',"&Uacute;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00DB',"&Ucirc;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00DC',"&Uuml;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00DD',"&Yacute;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00DE',"&THORN;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00DF',"&szlig;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00E0',"&agrave;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00E1',"&aacute;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00E2',"&acirc;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00E3',"&atilde;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00E4',"&auml;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00E5',"&aring;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00E6',"&aelig;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00E7',"&ccedil;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00E8',"&egrave;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00E9',"&eacute;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00EA',"&ecirc;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00EB',"&euml;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00EC',"&igrave;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00ED',"&iacute;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00EE',"&icirc;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00EF',"&iuml;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00F0',"&eth;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00F1',"&ntilde;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00F2',"&ograve;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00F3',"&oacute;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00F4',"&ocirc;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00F5',"&otilde;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00F6',"&ouml;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00F7',"&divide;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00F8',"&oslash;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00F9',"&ugrave;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00FA',"&uacute;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00FB',"&ucirc;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00FC',"&uuml;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00FD',"&yacute;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00FE',"&thorn;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u00FF',"&yuml;");
        // Mathematical, Greek and Symbolic characters for HTML
        DEFENSIVE_HTML_ENCODE_MAP.put('\u0192',"&fnof;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u0391',"&Alpha;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u0392',"&Beta;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u0393',"&Gamma;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u0394',"&Delta;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u0395',"&Epsilon;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u0396',"&Zeta;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u0397',"&Eta;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u0398',"&Theta;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u0399',"&Iota;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u039A',"&Kappa;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u039B',"&Lambda;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u039C',"&Mu;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u039D',"&Nu;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u039E',"&Xi;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u039F',"&Omicron;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03A0',"&Pi;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03A1',"&Rho;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03A3',"&Sigma;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03A4',"&Tau;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03A5',"&Upsilon;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03A6',"&Phi;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03A7',"&Chi;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03A8',"&Psi;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03A9',"&Omega;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03B1',"&alpha;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03B2',"&beta;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03B3',"&gamma;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03B4',"&delta;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03B5',"&epsilon;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03B6',"&zeta;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03B7',"&eta;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03B8',"&theta;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03B9',"&iota;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03BA',"&kappa;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03BB',"&lambda;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03BC',"&mu;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03BD',"&nu;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03BE',"&xi;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03BF',"&omicron;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03C0',"&pi;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03C1',"&rho;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03C2',"&sigmaf;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03C3',"&sigma;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03C4',"&tau;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03C5',"&upsilon;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03C6',"&phi;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03C7',"&chi;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03C8',"&psi;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03C9',"&omega;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03D1',"&thetasym;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03D2',"&upsih;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u03D6',"&piv;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2022',"&bull;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2026',"&hellip;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2032',"&prime;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2033',"&Prime;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u203E',"&oline;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2044',"&frasl;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2118',"&weierp;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2111',"&image;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u211C',"&real;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2122',"&trade;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2135',"&alefsym;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2190',"&larr;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2191',"&uarr;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2192',"&rarr;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2193',"&darr;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2194',"&harr;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u21B5',"&crarr;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u21D0',"&lArr;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u21D1',"&uArr;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u21D2',"&rArr;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u21D3',"&dArr;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u21D4',"&hArr;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2200',"&forall;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2202',"&part;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2203',"&exist;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2205',"&empty;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2207',"&nabla;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2208',"&isin;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2209',"&notin;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u220B',"&ni;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u220F',"&prod;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2211',"&sum;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2212',"&minus;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2217',"&lowast;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u221A',"&radic;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u221D',"&prop;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u221E',"&infin;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2220',"&ang;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2227',"&and;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2228',"&or;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2229',"&cap;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u222A',"&cup;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u222B',"&int;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2234',"&there4;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u223C',"&sim;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2245',"&cong;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2248',"&asymp;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2260',"&ne;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2261',"&equiv;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2264',"&le;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2265',"&ge;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2282',"&sub;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2283',"&sup;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2284',"&nsub;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2286',"&sube;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2287',"&supe;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2295',"&oplus;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2297',"&otimes;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u22A5',"&perp;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u22C5',"&sdot;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2308',"&lceil;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2309',"&rceil;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u230A',"&lfloor;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u230B',"&rfloor;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2329',"&lang;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u232A',"&rang;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u25CA',"&loz;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2660',"&spades;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2663',"&clubs;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2665',"&hearts;");
        DEFENSIVE_HTML_ENCODE_MAP.put('\u2666',"&diams;");
        Set<Map.Entry<Character, String>> aggresive_entries = AGGRESSIVE_HTML_ENCODE_MAP.entrySet();
        for (Map.Entry<Character, String> entry : aggresive_entries)
        {
            HTML_DECODE_MAP.put(entry.getValue(), entry.getKey());
        }
        Set<Map.Entry<Character, String>> defensive_entries = DEFENSIVE_HTML_ENCODE_MAP.entrySet();
        for (Map.Entry<Character, String> entry : defensive_entries)
        {
            HTML_DECODE_MAP.put(entry.getValue(), entry.getKey());
        }
        XML_ENCODE_MAP.put('\u0026',"&amp;");
        XML_ENCODE_MAP.put('\'',"&apos;");
        XML_ENCODE_MAP.put('\u0022',"&quot;");
        XML_ENCODE_MAP.put('\u003C',"&lt;");
        XML_ENCODE_MAP.put('\u003E',"&gt;");
        SQL_ENCODE_MAP.put('\'',"''");
        STRING_ENCODE_MAP.put('\\',"\\\\");
        STRING_ENCODE_MAP.put('\n',"\\n");
        STRING_ENCODE_MAP.put('\r',"\\r");
        STRING_ENCODE_MAP.put('\t',"\\t");
        STRING_ENCODE_MAP.put('"',"\\\"");
        LATEX_ENCODE_MAP.put('\\',"\\\\");
        LATEX_ENCODE_MAP.put('#',"\\#");
        LATEX_ENCODE_MAP.put('$',"\\$");
        LATEX_ENCODE_MAP.put('%',"\\%");
        LATEX_ENCODE_MAP.put('&',"\\&");
        LATEX_ENCODE_MAP.put('~',"\\~");
        LATEX_ENCODE_MAP.put('_',"\\_");
        LATEX_ENCODE_MAP.put('^',"\\^");
        LATEX_ENCODE_MAP.put('{',"\\{");
        LATEX_ENCODE_MAP.put('}',"\\}");
        LATEX_ENCODE_MAP.put('\u00A1',"!'");
        LATEX_ENCODE_MAP.put('\u00BF',"?'");
        LATEX_ENCODE_MAP.put('\u00C0',"\\`{A}");
        LATEX_ENCODE_MAP.put('\u00C1',"\\'{A}");
        LATEX_ENCODE_MAP.put('\u00C2',"\\^{A}");
        LATEX_ENCODE_MAP.put('\u00C3',"\\H{A}");
        LATEX_ENCODE_MAP.put('\u00C4',"\\\"{A}");
        LATEX_ENCODE_MAP.put('\u00C5',"\\AA");
        LATEX_ENCODE_MAP.put('\u00C6',"\\AE");
        LATEX_ENCODE_MAP.put('\u00C7',"\\c{C}");
        LATEX_ENCODE_MAP.put('\u00C8',"\\`{E}");
        LATEX_ENCODE_MAP.put('\u00C9',"\\'{E}");
        LATEX_ENCODE_MAP.put('\u00CA',"\\^{E}");
        LATEX_ENCODE_MAP.put('\u00CB',"\\\"{E}");
        LATEX_ENCODE_MAP.put('\u00CC',"\\`{I}");
        LATEX_ENCODE_MAP.put('\u00CD',"\\'{I}");
        LATEX_ENCODE_MAP.put('\u00CE',"\\^{I}");
        LATEX_ENCODE_MAP.put('\u00CF',"\\\"{I}");
// todo \u00D0
        LATEX_ENCODE_MAP.put('\u00D1',"\\H{N}");
        LATEX_ENCODE_MAP.put('\u00D2',"\\`{O}");
        LATEX_ENCODE_MAP.put('\u00D3',"\\'{O}");
        LATEX_ENCODE_MAP.put('\u00D4',"\\^{O}");
        LATEX_ENCODE_MAP.put('\u00D5',"\\H{O}");
        LATEX_ENCODE_MAP.put('\u00D6',"\\\"{O}");
// todo \u00D7
        LATEX_ENCODE_MAP.put('\u00D8',"\\O");
        LATEX_ENCODE_MAP.put('\u00D9',"\\`{U}");
        LATEX_ENCODE_MAP.put('\u00DA',"\\'{U}");
        LATEX_ENCODE_MAP.put('\u00DB',"\\^{U}");
        LATEX_ENCODE_MAP.put('\u00DC',"\\\"{U}");
        LATEX_ENCODE_MAP.put('\u00DD',"\\'{Y}");
// todo \u00DE
        LATEX_ENCODE_MAP.put('\u00DF',"\\ss");
        LATEX_ENCODE_MAP.put('\u00E0',"\\`{a}");
        LATEX_ENCODE_MAP.put('\u00E1',"\\'{a}");
        LATEX_ENCODE_MAP.put('\u00E2',"\\^{a}");
        LATEX_ENCODE_MAP.put('\u00E3',"\\H{a}");
        LATEX_ENCODE_MAP.put('\u00E4',"\\\"{a}");
        LATEX_ENCODE_MAP.put('\u00E5',"\\aa");
        LATEX_ENCODE_MAP.put('\u00E6',"\\ae");
        LATEX_ENCODE_MAP.put('\u00E7',"\\c{c}");
        LATEX_ENCODE_MAP.put('\u00E8',"\\`{e}");
        LATEX_ENCODE_MAP.put('\u00E9',"\\'{e}");
        LATEX_ENCODE_MAP.put('\u00EA',"\\^{e}");
        LATEX_ENCODE_MAP.put('\u00EB',"\\\"{e}");
        LATEX_ENCODE_MAP.put('\u00EC',"\\`{i}");
        LATEX_ENCODE_MAP.put('\u00ED',"\\'{i}");
        LATEX_ENCODE_MAP.put('\u00EE',"\\^{i}");
        LATEX_ENCODE_MAP.put('\u00EF',"\\\"{i}");
// todo \u00F0
        LATEX_ENCODE_MAP.put('\u00F1',"\\H{n}");
        LATEX_ENCODE_MAP.put('\u00F2',"\\`{o}");
        LATEX_ENCODE_MAP.put('\u00F3',"\\'{o}");
        LATEX_ENCODE_MAP.put('\u00F4',"\\^{o}");
        LATEX_ENCODE_MAP.put('\u00F5',"\\H{o}");
        LATEX_ENCODE_MAP.put('\u00F6',"\\\"{o}");
// todo \u00F7
        LATEX_ENCODE_MAP.put('\u00F8',"\\o");
        LATEX_ENCODE_MAP.put('\u00F9',"\\`{u}");
        LATEX_ENCODE_MAP.put('\u00FA',"\\'{u}");
        LATEX_ENCODE_MAP.put('\u00FB',"\\^{u}");
        LATEX_ENCODE_MAP.put('\u00FC',"\\\"{u}");
        LATEX_ENCODE_MAP.put('\u00FD',"\\'{y}");
// todo \u00FE
        LATEX_ENCODE_MAP.put('\u00FF',"\\\"{y}");
    }
    /**
     * Transforms a provided <code>String</code> object into a new string,
     * containing only valid characters for a java class name.
     *
     * @param name The string that has to be transformed into a valid class
     * name.
     * @return The encoded <code>String</code> object.
     * @see #encodeUrl(String)
     * @see #encodeHtml(String)
     * @see #encodeXml(String)
     * @see #encodeSql(String)
     * @see #encodeLatex(String)
     * @see #encodeRegexp(String)
     * @since 1.0
     */
    public static String encodeClassname(String name)
    {
        if (null == name)
        {
            return null;
        }
        Pattern pattern = Pattern.compile("[^\\w]");
        Matcher matcher = pattern.matcher(name);
        return matcher.replaceAll("_");
    }
    private static boolean needsUrlEncoding(String source)
    {
        if (null == source)
        {
            return false;
        }
        // check if the string needs encoding first since
        // the URLEncoder always allocates a StringBuffer, even when the
        // string is returned as-is
        boolean encode = false;
        char ch;
        for (int i = 0; i < source.length(); i++)
        {
            ch = source.charAt(i);
            if (ch >= 'a' && ch <= 'z' ||
                ch >= 'A' && ch <= 'Z' ||
                ch >= '0' && ch <= '9' ||
                ch == '-' || ch == '_' || ch == '.' || ch == '*')
            {
                continue;
            }
            encode = true;
            break;
        }
        return encode;
    }
    /**
     * Transforms a provided <code>String</code> object into a new string,
     * containing only valid URL characters.
     *
     * @param source The string that has to be transformed into a valid URL
     * string.
     * @return The encoded <code>String</code> object.
     * @see #encodeClassname(String)
     * @see #encodeUrlValue(String)
     * @see #encodeHtml(String)
     * @see #encodeXml(String)
     * @see #encodeSql(String)
     * @see #encodeLatex(String)
     * @see #encodeRegexp(String)
     * @since 1.0
     */
    public static String encodeUrl(String source)
    {
        if (!needsUrlEncoding(source))
        {
            return source;
        }
        try
        {
            return URLEncoder.encode(source, ENCODING_ISO_8859_1);
        }
        ///CLOVER:OFF
        catch (UnsupportedEncodingException e)
        {
            // this should never happen, ISO-8859-1 is a standard encoding
            throw new RuntimeException(e);
        }
        ///CLOVER:ON
    }
    /**
     * Transforms a provided <code>String</code> object into a new string,
     * only pure US Ascii strings are preserved and URL encoded in a regular
     * way. Strings with characters from other encodings will be encoded in a
     * RIFE-specific manner to allow international data to passed along the
     * query string.
     *
     * @param source The string that has to be transformed into a valid URL
     * parameter string.
     * @return The encoded <code>String</code> object.
     * @see #decodeUrlValue(String)
     * @see #encodeClassname(String)
     * @see #encodeUrl(String)
     * @see #encodeHtml(String)
     * @see #encodeXml(String)
     * @see #encodeSql(String)
     * @see #encodeLatex(String)
     * @see #encodeRegexp(String)
     * @since 1.0
     */
    public static String encodeUrlValue(String source)
    {
        if (!needsUrlEncoding(source))
        {
            return source;
        }
        // check if the string is valid US-ASCII encoding
        boolean         valid = true;
        CharsetEncoder encoder = CHARSET_US_ASCII.newEncoder();
        try
        {
            encoder.encode(CharBuffer.wrap(source));
        }
        catch (CharacterCodingException e)
        {
            valid = false;
        }
        try
        {
            // if it is valid US-ASCII, use the regular URL encoding method
            if (valid)
            {
                    return URLEncoder.encode(source, ENCODING_US_ASCII);
            }
            // otherwise, base-64 encode the UTF-8 bytes and mark the string
            // as being encoded in a special way
            else
            {
                StringBuilder encoded = new StringBuilder("%02%02");
                String base64 = Base64.encodeToString(source.getBytes(ENCODING_UTF_8), false);
                String base64_urlsafe = replace(base64, "=", "%3D");
                encoded.append(base64_urlsafe);
                return encoded.toString();
            }
        }
        ///CLOVER:OFF
        catch (UnsupportedEncodingException e)
        {
            // this should never happen, ISO-8859-1 is a standard encoding
            throw new RuntimeException(e);
        }
        ///CLOVER:ON
    }
    /**
     * Decodes a <code>String</code> that has been encoded in a RIFE-specific
     * manner for URL usage.. Before calling this method, you should first
     * verify if the value needs decoding by using the
     * <code>doesUrlValueNeedDecoding(String)</code> method.
     *
     * @param source the value that has been encoded for URL usage in a
     * RIFE-specific way
     * @return The decoded <code>String</code> object.
     * @see #encodeUrlValue(String)
     * @see #doesUrlValueNeedDecoding(String)
     * @since 1.0
     */
    public static String decodeUrlValue(String source)
    {
        try
        {
            byte[] decoded = Base64.decode(source.substring(2));
            if (null == decoded)
            {
                return null;
            }
            else
            {
                return new String(decoded, StringUtils.ENCODING_UTF_8);
            }
        }
        ///CLOVER:OFF
        catch (UnsupportedEncodingException e)
        {
            // this should never happen, UTF-8 is a standard encoding
            throw new RuntimeException(e);
        }
        ///CLOVER:ON
    }
    /**
     * Checks if a <code>String</code> is encoded in a RIFE-specific manner
     * for URL usage.
     *
     * @param source the value that might have been encoded for URL usage in a
     * RIFE-specific way
     * @return <code>true</code> if the value is encoded in the RIFE-specific
     * format; and
     * <p><code>false</code> otherwise
     * @see #encodeUrlValue(String)
     * @see #decodeUrlValue(String)
     * @since 1.0
     */
    public static boolean doesUrlValueNeedDecoding(String source)
    {
        if (source != null &&
            source.length() > 2 &&
            source.startsWith("\u0002\u0002"))
        {
            return true;
        }
        return false;
    }
    private static boolean needsHtmlEncoding(String source, boolean defensive)
    {
        if (null == source)
        {
            return false;
        }
        boolean encode = false;
        char ch;
        for (int i = 0; i < source.length(); i++)
        {
            ch = source.charAt(i);
            if ((defensive || (ch != '\u0022' && ch != '\u0026' && ch != '\u003C' && ch != '\u003E')) &&
                ch < '\u00A0')
            {
                continue;
            }
            encode = true;
            break;
        }
        return encode;
    }
    /**
     *
     * @since 1.6
     */
    public static String decodeHtml(String source)
    {
        if (null == source ||
            0 == source.length())
        {
            return source;
        }
        int        current_index = 0;
        int        delimiter_start_index = 0;
        int        delimiter_end_index = 0;
        StringBuilder result = null;
        while (current_index <= source.length())
        {
            delimiter_start_index = source.indexOf('&', current_index);
            if (delimiter_start_index != -1)
            {
                delimiter_end_index = source.indexOf(';', delimiter_start_index + 1);
                if (delimiter_end_index != -1)
                {
                    // ensure that the string builder is setup correctly
                    if (null == result)
                    {
                        result = new StringBuilder();
                    }
                    // add the text that leads up to this match
                    if (delimiter_start_index > current_index)
                    {
                        result.append(source.substring(current_index, delimiter_start_index));
                    }
                    // add the decoded entity
                    String entity = source.substring(delimiter_start_index, delimiter_end_index + 1);
                    current_index = delimiter_end_index + 1;
                    // try to decoded numeric entities
                    if (entity.charAt(1) == '#')
                    {
                        int start = 2;
                        int radix = 10;
                        // check if the number is hexadecimal
                        if (entity.charAt(2) == 'X' || entity.charAt(2) == 'x')
                        {
                            start++;
                            radix = 16;
                        }
                        try
                        {
                            Character c = new Character((char)Integer.parseInt(entity.substring(start, entity.length() - 1), radix));
                            result.append(c);
                        }
                        // when the number of the entity can't be parsed, add the entity as-is
                        catch (NumberFormatException e)
                        {
                            result.append(entity);
                        }
                    }
                    else
                    {
                        // try to decode the entity as a literal
                        Character decoded = HTML_DECODE_MAP.get(entity);
                        if (decoded != null)
                        {
                            result.append(decoded);
                        }
                        // if there was no match, add the entity as-is
                        else
                        {
                            result.append(entity);
                        }
                    }
                }
                else
                {
                    break;
                }
            }
            else
            {
                break;
            }
        }
        if (null == result)
        {
            return source;
        }
        else if (current_index < source.length())
        {
            result.append(source.substring(current_index));
        }
        return result.toString();
    }
    /**
     * Transforms a provided <code>String</code> object into a new string,
     * containing only valid Html characters.
     *
     * @param source The string that has to be transformed into a valid Html
     * string.
     * @return The encoded <code>String</code> object.
     * @see #encodeClassname(String)
     * @see #encodeUrl(String)
     * @see #encodeUrlValue(String)
     * @see #encodeXml(String)
     * @see #encodeSql(String)
     * @see #encodeString(String)
     * @see #encodeLatex(String)
     * @see #encodeRegexp(String)
     * @since 1.0
     */
    public static String encodeHtml(String source)
    {
        if (needsHtmlEncoding(source, false))
        {
            return encode(source, HTML_ENCODER_FALLBACK, AGGRESSIVE_HTML_ENCODE_MAP, DEFENSIVE_HTML_ENCODE_MAP);
        }
        return source;
    }
    /**
     * Transforms a provided <code>String</code> object into a new string,
     * containing as much as possible Html characters. It is safe to already
     * feed existing Html to this method since &amp;, &lt; and &gt; will not
     * be encoded.
     *
     * @param source The string that has to be transformed into a valid Html
     * string.
     * @return The encoded <code>String</code> object.
     * @see #encodeClassname(String)
     * @see #encodeUrl(String)
     * @see #encodeUrlValue(String)
     * @see #encodeXml(String)
     * @see #encodeSql(String)
     * @see #encodeString(String)
     * @see #encodeLatex(String)
     * @see #encodeRegexp(String)
     * @since 1.0
     */
    public static String encodeHtmlDefensive(String source)
    {
        if (needsHtmlEncoding(source, true))
        {
            return encode(source, null, DEFENSIVE_HTML_ENCODE_MAP);
        }
        return source;
    }
    /**
     * Transforms a provided <code>String</code> object into a new string,
     * containing only valid XML characters.
     *
     * @param source The string that has to be transformed into a valid XML
     * string.
     * @return The encoded <code>String</code> object.
     * @see #encodeClassname(String)
     * @see #encodeUrl(String)
     * @see #encodeUrlValue(String)
     * @see #encodeHtml(String)
     * @see #encodeSql(String)
     * @see #encodeString(String)
     * @see #encodeLatex(String)
     * @see #encodeRegexp(String)
     * @since 1.0
     */
    public static String encodeXml(String source)
    {
        return encode(source, null, XML_ENCODE_MAP);
    }
    /**
     * Transforms a provided <code>String</code> object into a new string,
     * containing only valid <code>String</code> characters.
     *
     * @param source The string that has to be transformed into a valid
     * sequence of <code>String</code> characters.
     * @return The encoded <code>String</code> object.
     * @see #encodeClassname(String)
     * @see #encodeUrl(String)
     * @see #encodeUrlValue(String)
     * @see #encodeHtml(String)
     * @see #encodeXml(String)
     * @see #encodeSql(String)
     * @see #encodeLatex(String)
     * @see #encodeRegexp(String)
     * @since 1.0
     */
    public static String encodeString(String source)
    {
        return encode(source, null, STRING_ENCODE_MAP);
    }
    /**
     * Transforms a provided <code>String</code> object into a series of
     * unicode escape codes.
     *
     * @param source The string that has to be transformed into a valid
     * sequence of unicode escape codes
     * @return The encoded <code>String</code> object.
     * @see #encodeClassname(String)
     * @see #encodeUrl(String)
     * @see #encodeUrlValue(String)
     * @see #encodeHtml(String)
     * @see #encodeXml(String)
     * @see #encodeSql(String)
     * @see #encodeLatex(String)
     * @see #encodeRegexp(String)
     * @since 1.0
     */
    public static String encodeUnicode(String source)
    {
        if (null == source)
        {
            return null;
        }
        StringBuilder    encoded = new StringBuilder();
        String            hexstring = null;
        for (int i = 0; i < source.length(); i++)
        {
            hexstring = Integer.toHexString((int)source.charAt(i)).toUpperCase();
            encoded.append("\\u");
            // fill with zeros
            for (int j = hexstring.length(); j < 4; j++)
            {
                encoded.append("0");
            }
            encoded.append(hexstring);
        }
        return encoded.toString();
    }
    /**
     * Transforms a provided <code>String</code> object into a new string,
     * containing only valid Sql characters.
     *
     * @param source The string that has to be transformed into a valid Sql
     * string.
     * @return The encoded <code>String</code> object.
     * @see #encodeClassname(String)
     * @see #encodeUrl(String)
     * @see #encodeUrlValue(String)
     * @see #encodeHtml(String)
     * @see #encodeXml(String)
     * @see #encodeString(String)
     * @see #encodeLatex(String)
     * @see #encodeRegexp(String)
     * @since 1.0
     */
    public static String encodeSql(String source)
    {
        return encode(source, null, SQL_ENCODE_MAP);
    }
    /**
     * Transforms a provided <code>String</code> object into a new string,
     * containing only valid LaTeX characters.
     *
     * @param source The string that has to be transformed into a valid LaTeX
     * string.
     * @return The encoded <code>String</code> object.
     * @see #encodeClassname(String)
     * @see #encodeUrl(String)
     * @see #encodeUrlValue(String)
     * @see #encodeHtml(String)
     * @see #encodeXml(String)
     * @see #encodeSql(String)
     * @see #encodeString(String)
     * @see #encodeRegexp(String)
     * @since 1.0
     */
    public static String encodeLatex(String source)
    {
        if (null == source)
        {
            return null;
        }
        source = encode(source, null, LATEX_ENCODE_MAP);
        source = StringUtils.replace(source, "latex", "\\LaTeX", false);
        return source;
    }
    /**
     * Transforms a provided <code>String</code> object into a new string,
     * using the mapping that are provided through the supplied encoding
     * table.
     *
     * @param source The string that has to be transformed into a valid
     * string, using the mappings that are provided through the supplied
     * encoding table.
     * @param encodingTables A <code>Map</code> object containing the mappings
     * to transform characters into valid entities. The keys of this map
     * should be <code>Character</code> objects and the values
     * <code>String</code> objects.
     * @return The encoded <code>String</code> object.
     * @since 1.0
     */
    private static String encode(String source, EncoderFallbackHandler fallbackHandler, Map<Character, String>... encodingTables)
    {
        if (null == source)
        {
            return null;
        }
        if (null == encodingTables ||
            0 == encodingTables.length)
        {
            return source;
        }
        StringBuilder    encoded_string = null;
        char[]            string_to_encode_array = source.toCharArray();
        int                last_match = -1;
        for (int i = 0; i < string_to_encode_array.length; i++)
        {
            char char_to_encode = string_to_encode_array[i];
            for (Map<Character, String> encoding_table : encodingTables)
            {
                if (encoding_table.containsKey(char_to_encode))
                {
                    encoded_string = prepareEncodedString(source, encoded_string, i, last_match, string_to_encode_array);
                    encoded_string.append(encoding_table.get(char_to_encode));
                    last_match = i;
                }
            }
            if (fallbackHandler != null &&
                last_match < i &&
                fallbackHandler.hasFallback(char_to_encode))
            {
                encoded_string = prepareEncodedString(source, encoded_string, i, last_match, string_to_encode_array);
                fallbackHandler.appendFallback(encoded_string, char_to_encode);
                last_match = i;
            }
        }
        if (null == encoded_string)
        {
            return source;
        }
        else
        {
            int difference = string_to_encode_array.length-(last_match+1);
            if (difference > 0)
            {
                encoded_string.append(string_to_encode_array, last_match+1, difference);
            }
            return encoded_string.toString();
        }
    }
    private static StringBuilder prepareEncodedString(String source, StringBuilder encodedString, int i, int lastMatch, char[] stringToEncodeArray)
    {
        if (null == encodedString)
        {
            encodedString = new StringBuilder(source.length());
        }
        int difference = i - (lastMatch + 1);
        if (difference > 0)
        {
            encodedString.append(stringToEncodeArray, lastMatch + 1, difference);
        }
        return encodedString;
    }
    private static interface EncoderFallbackHandler
    {
        abstract boolean hasFallback(char character);
        abstract void appendFallback(StringBuilder encodedBuffer, char character);
    }
    private static class HtmlEncoderFallbackHandler implements EncoderFallbackHandler
    {
        private final static String PREFIX = "&#";
        private final static String SUFFIX = ";";
        public boolean hasFallback(char character)
        {
            if (character < '\u00A0')
            {
                return false;
            }
            return true;
        }
        public void appendFallback(StringBuilder encodedBuffer, char character)
        {
            encodedBuffer.append(PREFIX);
            encodedBuffer.append((int)character);
            encodedBuffer.append(SUFFIX);
        }
    }
    /**
     * Transforms a provided <code>String</code> object into a literal that can
     * be included into a regular expression {@link Pattern} as-is. None of the
     * regular expression escapes in the string will be functional anymore.
     *
     * @param source The string that has to be escaped as a literal
     * @return The encoded <code>String</code> object.
     * @see #encodeClassname(String)
     * @see #encodeUrl(String)
     * @see #encodeUrlValue(String)
     * @see #encodeHtml(String)
     * @see #encodeXml(String)
     * @see #encodeSql(String)
     * @see #encodeString(String)
     * @see #encodeLatex(String)
     * @since 1.3
     */
    public static String encodeRegexp(String source)
    {
        int regexp_quote_start = source.indexOf("\\E");
        if (-1 == regexp_quote_start)
        {
            return "\\Q" + source + "\\E";
        }
        StringBuilder buffer = new StringBuilder(source.length() * 2);
        buffer.append("\\Q");
        regexp_quote_start = 0;
        int current = 0;
        while (-1 == (regexp_quote_start = source.indexOf("\\E", current)))
        {
            buffer.append(source.substring(current, regexp_quote_start));
            current = regexp_quote_start + 2;
            buffer.append("\\E\\\\E\\Q");
        }
        buffer.append(source.substring(current, source.length()));
        buffer.append("\\E");
        return buffer.toString();
    }
    /**
     * Counts the number of times a substring occures in a provided string in
     * a case-sensitive manner.
     *
     * @param source The <code>String</code> object that will be searched in.
     * @param substring The string whose occurances will we counted.
     * @return An <code>int</code> value containing the number of occurances
     * of the substring.
     * @since 1.0
     */
    public static int count(String source, String substring)
    {
        return count(source, substring, true);
    }
    /**
     * Counts the number of times a substring occures in a provided string.
     *
     * @param source The <code>String</code> object that will be searched in.
     * @param substring The string whose occurances will we counted.
     * @param matchCase A <code>boolean</code> indicating if the match is
     * going to be performed in a case-sensitive manner or not.
     * @return An <code>int</code> value containing the number of occurances
     * of the substring.
     * @since 1.0
     */
    public static int count(String source, String substring, boolean matchCase)
    {
        if (null == source)
        {
            return 0;
        }
        if (null == substring)
        {
            return 0;
        }
        int current_index = 0;
        int substring_index = 0;
        int count = 0;
        if (!matchCase)
        {
            source = source.toLowerCase();
            substring = substring.toLowerCase();
        }
        while (current_index < source.length()-1)
        {
            substring_index = source.indexOf(substring, current_index);
            if (-1 == substring_index)
            {
                break;
            }
            else
            {
                current_index = substring_index + substring.length();
                count++;
            }
        }
        return count;
    }
    /**
     * Splits a string into different parts, using a seperator string to
     * detect the seperation boundaries in a case-sensitive manner. The
     * seperator will not be included in the list of parts.
     *
     * @param source The string that will be split into parts.
     * @param seperator The seperator string that will be used to determine
     * the parts.
     * @return An <code>ArrayList</code> containing the parts as
     * <code>String</code> objects.
     * @since 1.0
     */
    public static ArrayList<String> split(String source, String seperator)
    {
        return split(source, seperator, true);
    }
    /**
     * Splits a string into different parts, using a seperator string to
     * detect the seperation boundaries. The seperator will not be included in
     * the list of parts.
     *
     * @param source The string that will be split into parts.
     * @param seperator The seperator string that will be used to determine
     * the parts.
     * @param matchCase A <code>boolean</code> indicating if the match is
     * going to be performed in a case-sensitive manner or not.
     * @return An <code>ArrayList</code> containing the parts as
     * <code>String</code> objects.
     * @since 1.0
     */
    public static ArrayList<String> split(String source, String seperator, boolean matchCase)
    {
        ArrayList<String>   substrings = new ArrayList<String>();
        if (null == source)
        {
            return substrings;
        }
        if (null == seperator)
        {
            substrings.add(source);
            return substrings;
        }
        int        current_index = 0;
        int        delimiter_index = 0;
        String    element = null;
        String  source_lookup_reference = null;
        if (!matchCase)
        {
            source_lookup_reference = source.toLowerCase();
            seperator = seperator.toLowerCase();
        }
        else
        {
            source_lookup_reference = source;
        }
        while (current_index <= source_lookup_reference.length())
        {
            delimiter_index = source_lookup_reference.indexOf(seperator, current_index);
            if (-1 == delimiter_index)
            {
                element = new String(source.substring(current_index, source.length()));
                substrings.add(element);
                current_index = source.length() + 1;
            }
            else
            {
                element = new String(source.substring(current_index, delimiter_index));
                substrings.add(element);
                current_index = delimiter_index + seperator.length();
            }
        }
        return substrings;
    }
    /**
     * Splits a string into different parts, using a seperator string to
     * detect the seperation boundaries in a case-sensitive manner. The
     * seperator will not be included in the parts array.
     *
     * @param source The string that will be split into parts.
     * @param seperator The seperator string that will be used to determine
     * the parts.
     * @return A <code>String[]</code> array containing the seperated parts.
     * @since 1.0
     */
    public static String[] splitToArray(String source, String seperator)
    {
        return splitToArray(source, seperator, true);
    }
    /**
     * Splits a string into different parts, using a seperator string to
     * detect the seperation boundaries. The seperator will not be included in
     * the parts array.
     *
     * @param source The string that will be split into parts.
     * @param seperator The seperator string that will be used to determine
     * the parts.
     * @param matchCase A <code>boolean</code> indicating if the match is
     * going to be performed in a case-sensitive manner or not.
     * @return A <code>String[]</code> array containing the seperated parts.
     * @since 1.0
     */
    public static String[] splitToArray(String source, String seperator, boolean matchCase)
    {
        ArrayList<String>   substrings = split(source, seperator, matchCase);
        String[]            substrings_array = new String[substrings.size()];
        substrings_array = substrings.toArray(substrings_array);
        return substrings_array;
    }
    /**
     * Splits a string into integers, using a seperator string to detect the
     * seperation boundaries in a case-sensitive manner. If a part couldn't be
     * converted to an integer, it will be omitted from the resulting array.
     *
     * @param source The string that will be split into integers.
     * @param seperator The seperator string that will be used to determine
     * the parts.
     * @return An <code>int[]</code> array containing the seperated parts.
     * @since 1.0
     */
    public static int[] splitToIntArray(String source, String seperator)
    {
        return splitToIntArray(source, seperator, true);
    }
    /**
     * Splits a string into integers, using a seperator string to detect the
     * seperation boundaries. If a part couldn't be converted to an integer,
     * it will be omitted from the resulting array.
     *
     * @param source The string that will be split into integers.
     * @param seperator The seperator string that will be used to determine
     * the parts.
     * @param matchCase A <code>boolean</code> indicating if the match is
     * going to be performed in a case-sensitive manner or not.
     * @return An <code>int[]</code> array containing the seperated parts.
     * @since 1.0
     */
    public static int[] splitToIntArray(String source, String seperator, boolean matchCase)
    {
        ArrayList<String>   string_parts = split(source, seperator, matchCase);
        int                 number_of_valid_parts = 0;
        for (String string_part : string_parts)
        {
            try
            {
                Integer.parseInt(string_part);
                number_of_valid_parts++;
            }
            catch (NumberFormatException e)
            {
                // just continue
            }
        }
        int[]   string_parts_int = (int[]) Array.newInstance(int.class, number_of_valid_parts);
        int     added_parts = 0;
        for (String string_part : string_parts)
        {
            try
            {
                string_parts_int[added_parts] = Integer.parseInt(string_part);
                added_parts++;
            }
            catch (NumberFormatException e)
            {
                // just continue
            }
        }
        return string_parts_int;
    }
    /**
     * Splits a string into bytes, using a seperator string to detect the
     * seperation boundaries in a case-sensitive manner. If a part couldn't be
     * converted to a <code>byte</code>, it will be omitted from the resulting
     * array.
     *
     * @param source The string that will be split into bytes.
     * @param seperator The seperator string that will be used to determine
     * the parts.
     * @return A <code>byte[]</code> array containing the bytes.
     * @since 1.0
     */
    public static byte[] splitToByteArray(String source, String seperator)
    {
        return splitToByteArray(source, seperator, true);
    }
    /**
     * Splits a string into bytes, using a seperator string to detect the
     * seperation boundaries. If a part couldn't be converted to a
     * <code>byte</code>, it will be omitted from the resulting array.
     *
     * @param source The string that will be split into bytes.
     * @param seperator The seperator string that will be used to determine
     * the parts.
     * @param matchCase A <code>boolean</code> indicating if the match is
     * going to be performed in a case-sensitive manner or not.
     * @return A <code>byte[]</code> array containing the bytes.
     * @since 1.0
     */
    public static byte[] splitToByteArray(String source, String seperator, boolean matchCase)
    {
        ArrayList<String>   string_parts = split(source, seperator, matchCase);
        int                 number_of_valid_parts = 0;
        for (String string_part : string_parts)
        {
            try
            {
                Byte.parseByte(string_part);
                number_of_valid_parts++;
            }
            catch (NumberFormatException e)
            {
                // just continue
            }
        }
        byte[]  string_parts_byte = (byte[])Array.newInstance(byte.class, number_of_valid_parts);
        int     added_parts = 0;
        for (String string_part : string_parts)
        {
            try
            {
                string_parts_byte[added_parts] = Byte.parseByte(string_part);
                added_parts++;
            }
            catch (NumberFormatException e)
            {
                // just continue
            }
        }
        return string_parts_byte;
    }
    /**
     * Removes all occurances of a string from the front of another string in
     * a case-sensitive manner.
     *
     * @param source The string in which the matching will be done.
     * @param stringToStrip The string that will be stripped from the front.
     * @return A new <code>String</code> containing the stripped result.
     * @since 1.0
     */
    public static String stripFromFront(String source, String stringToStrip)
    {
        return stripFromFront(source, stringToStrip, true);
    }
    /**
     * Removes all occurances of a string from the front of another string.
     *
     * @param source The string in which the matching will be done.
     * @param stringToStrip The string that will be stripped from the front.
     * @param matchCase A <code>boolean</code> indicating if the match is
     * going to be performed in a case-sensitive manner or not.
     * @return A new <code>String</code> containing the stripping result.
     * @since 1.0
     */
    public static String stripFromFront(String source, String stringToStrip, boolean matchCase)
    {
        if (null == source)
        {
            return null;
        }
        if (null == stringToStrip)
        {
            return source;
        }
        int strip_length = stringToStrip.length();
        int new_index = 0;
        int last_index = 0;
        String  source_lookup_reference = null;
        if (!matchCase)
        {
            source_lookup_reference = source.toLowerCase();
            stringToStrip = stringToStrip.toLowerCase();
        }
        else
        {
            source_lookup_reference = source;
        }
        new_index = source_lookup_reference.indexOf(stringToStrip);
        if (0 == new_index)
        {
            do
            {
                last_index = new_index;
                new_index = source_lookup_reference.indexOf(stringToStrip, new_index+strip_length);
            }
            while (new_index != -1 &&
                   new_index == last_index+strip_length);
            return source.substring(last_index+strip_length);
        }
        else
        {
            return source;
        }
    }
    /**
     * Removes all occurances of a string from the end of another string in a
     * case-sensitive manner.
     *
     * @param source The string in which the matching will be done.
     * @param stringToStrip The string that will be stripped from the end.
     * @return A new <code>String</code> containing the stripped result.
     * @since 1.0
     */
    public static String stripFromEnd(String source, String stringToStrip)
    {
        return stripFromEnd(source, stringToStrip, true);
    }
    /**
     * Removes all occurances of a string from the end of another string.
     *
     * @param source The string in which the matching will be done.
     * @param stringToStrip The string that will be stripped from the end.
     * @param matchCase A <code>boolean</code> indicating if the match is
     * going to be performed in a case-sensitive manner or not.
     * @return A new <code>String</code> containing the stripped result.
     * @since 1.0
     */
    public static String stripFromEnd(String source, String stringToStrip, boolean matchCase)
    {
        if (null == source)
        {
            return null;
        }
        if (null == stringToStrip)
        {
            return source;
        }
        int strip_length = stringToStrip.length();
        int new_index = 0;
        int last_index = 0;
        String  source_lookup_reference = null;
        if (!matchCase)
        {
            source_lookup_reference = source.toLowerCase();
            stringToStrip = stringToStrip.toLowerCase();
        }
        else
        {
            source_lookup_reference = source;
        }
        new_index = source_lookup_reference.lastIndexOf(stringToStrip);
        if (new_index != -1 &&
            source.length() == new_index+strip_length)
        {
            do
            {
                last_index = new_index;
                new_index = source_lookup_reference.lastIndexOf(stringToStrip, last_index-1);
            }
            while (new_index != -1 &&
                   new_index == last_index-strip_length);
            return source.substring(0, last_index);
        }
        else
        {
            return source;
        }
    }
    /**
     * Searches for a string within a specified string in a case-sensitive
     * manner and replaces every match with another string.
     *
     * @param source The string in which the matching parts will be replaced.
     * @param stringToReplace The string that will be searched for.
     * @param replacementString The string that will replace each matching
     * part.
     * @return A new <code>String</code> object containing the replacement
     * result.
     * @since 1.0
     */
    public static String replace(String source, String stringToReplace, String replacementString)
    {
        return replace(source, stringToReplace, replacementString, true);
    }
    /**
     * Searches for a string within a specified string and replaces every
     * match with another string.
     *
     * @param source The string in which the matching parts will be replaced.
     * @param stringToReplace The string that will be searched for.
     * @param replacementString The string that will replace each matching
     * part.
     * @param matchCase A <code>boolean</code> indicating if the match is
     * going to be performed in a case-sensitive manner or not.
     * @return A new <code>String</code> object containing the replacement
     * result.
     * @since 1.0
     */
    public static String replace(String source, String stringToReplace, String replacementString, boolean matchCase)
    {
        if (null == source)
        {
            return null;
        }
        if (null == stringToReplace)
        {
            return source;
        }
        if (null == replacementString)
        {
            return source;
        }
        Iterator<String> string_parts = split(source, stringToReplace, matchCase).iterator();
        StringBuilder        new_string = new StringBuilder();
        while (string_parts.hasNext())
        {
            String string_part = string_parts.next();
            new_string.append(string_part);
            if (string_parts.hasNext())
            {
                new_string.append(replacementString);
            }
        }
        return new_string.toString();
    }
    /**
     * Creates a new string that contains the provided string a number of
     * times.
     *
     * @param source The string that will be repeated.
     * @param count The number of times that the string will be repeated.
     * @return A new <code>String</code> object containing the repeated
     * concatenation result.
     * @since 1.0
     */
    public static String repeat(String source, int count)
    {
        if (null == source)
        {
            return null;
        }
        StringBuilder new_string = new StringBuilder();
        while (count > 0)
        {
            new_string.append(source);
            count --;
        }
        return new_string.toString();
    }
    /**
     * Creates a new array of <code>String</code> objects, containing the
     * elements of a supplied <code>Iterator</code>.
     *
     * @param iterator The iterator containing the elements to create the
     * array with.
     * @return The new <code>String</code> array.
     * @since 1.0
     */
    public static String[] toStringArray(Iterator<String> iterator)
    {
        if (null == iterator)
        {
            return new String[0];
        }
        ArrayList<String>   strings = new ArrayList<String>();
        while (iterator.hasNext())
        {
            strings.add(iterator.next());
        }
        String[] string_array = new String[strings.size()];
        strings.toArray(string_array);
        return string_array;
    }
    /**
     * Creates a new <code>ArrayList</code>, containing the elements of a
     * supplied array of <code>String</code> objects.
     *
     * @param stringArray The array of <code>String</code> objects that have
     * to be converted.
     * @return The new <code>ArrayList</code> with the elements of the
     * <code>String</code> array.
     * @since 1.0
     */
    public static ArrayList<String> toArrayList(String[] stringArray)
    {
        ArrayList<String> strings = new ArrayList<String>();
        if (null == stringArray)
        {
            return strings;
        }
        for (String element : stringArray)
        {
            strings.add(element);
        }
        return strings;
    }
    /**
     * Creates a new <code>String</code> object, containing the elements of a
     * supplied <code>Collection</code> of <code>String</code> objects joined
     * by a given seperator.
     *
     * @param collection The <code>Collection</code> containing the elements
     * to join.
     * @param seperator The seperator used to join the string elements.
     * @return A new <code>String</code> with the join result.
     * @since 1.0
     */
    public static String join(Collection collection, String seperator)
    {
        if (null == collection)
        {
            return null;
        }
        if (null == seperator)
        {
            seperator = "";
        }
        if (0 == collection.size())
        {
            return "";
        }
        else
        {
            StringBuilder result = new StringBuilder();
            for (Object element : collection)
            {
                result.append(String.valueOf(element));
                result.append(seperator);
            }
            result.setLength(result.length()-seperator.length());
            return result.toString();
        }
    }
    /**
     * Creates a new <code>String</code> object, containing the elements of a
     * supplied array, joined by a given seperator.
     *
     * @param array The object array containing the elements to join.
     * @param seperator The seperator used to join the string elements.
     * @return A new <code>String</code> with the join result.
     * @since 1.0
     */
    public static String join(Object[] array, String seperator)
    {
        return join(array, seperator, null, false);
    }
    /**
     * Creates a new <code>String</code> object, containing the elements of a
     * supplied array, joined by a given seperator.
     *
     * @param array The object array containing the elements to join.
     * @param seperator The seperator used to join the string elements.
     * @param delimiter The delimiter used to surround the string elements.
     * @return A new <code>String</code> with the join result.
     * @since 1.0
     */
    public static String join(Object[] array, String seperator, String delimiter)
    {
        return join(array, seperator, delimiter, false);
    }
    /**
     * Creates a new <code>String</code> object, containing the elements of a
     * supplied array, joined by a given seperator.
     *
     * @param array The object array containing the elements to join.
     * @param seperator The seperator used to join the string elements.
     * @param delimiter The delimiter used to surround the string elements.
     * @param encodeStrings Indicates whether the characters of the string
     * representation of the Array values should be encoded.
     * @return A new <code>String</code> with the join result.
     * @since 1.0
     */
    public static String join(Object[] array, String seperator, String delimiter, boolean encodeStrings)
    {
        if (null == array)
        {
            return null;
        }
        if (null == seperator)
        {
            seperator = "";
        }
        if (null == delimiter)
        {
            delimiter = "";
        }
        if (0 == array.length)
        {
            return "";
        }
        else
        {
            int                current_index = 0;
            String            array_value = null;
            StringBuilder    result = new StringBuilder();
            while (current_index < array.length - 1)
            {
                if (null == array[current_index])
                {
                    result.append("null");
                }
                else
                {
                    array_value = String.valueOf(array[current_index]);
                    if (encodeStrings)
                    {
                        array_value = encodeString(array_value);
                    }
                    result.append(delimiter);
                    result.append(array_value);
                    result.append(delimiter);
                }
                result.append(seperator);
                current_index++;
            }
            if (null == array[current_index])
            {
                result.append("null");
            }
            else
            {
                array_value = String.valueOf(array[current_index]);
                if (encodeStrings)
                {
                    array_value = encodeString(array_value);
                }
                result.append(delimiter);
                result.append(array_value);
                result.append(delimiter);
            }
            return result.toString();
        }
    }
    /**
     * Creates a new <code>String</code> object, containing the elements of a
     * supplied array, joined by a given seperator.
     *
     * @param array The boolean array containing the values to join.
     * @param seperator The seperator used to join the string elements.
     * @return A new <code>String</code> with the join result.
     * @since 1.0
     */
    public static String join(boolean[] array, String seperator)
    {
        if (null == array)
        {
            return null;
        }
        if (null == seperator)
        {
            seperator = "";
        }
        if (0 == array.length)
        {
            return "";
        }
        else
        {
            int current_index = 0;
            String result = "";
            while (current_index < array.length - 1)
            {
                result = result + array[current_index] + seperator;
                current_index++;
            }
            result = result +  array[current_index];
            return result;
        }
    }
    /**
     * Creates a new <code>String</code> object, containing the elements of a
     * supplied array, joined by a given seperator.
     *
     * @param array The byte array containing the values to join.
     * @param seperator The seperator used to join the string elements.
     * @return A new <code>String</code> with the join result.
     * @since 1.0
     */
    public static String join(byte[] array, String seperator)
    {
        if (null == array)
        {
            return null;
        }
        if (null == seperator)
        {
            seperator = "";
        }
        if (0 == array.length)
        {
            return "";
        }
        else
        {
            int current_index = 0;
            String result = "";
            while (current_index < array.length - 1)
            {
                result = result + array[current_index] + seperator;
                current_index++;
            }
            result = result +  array[current_index];
            return result;
        }
    }
    /**
     * Creates a new <code>String</code> object, containing the elements of a
     * supplied array, joined by a given seperator.
     *
     * @param array The double array containing the values to join.
     * @param seperator The seperator used to join the string elements.
     * @return A new <code>String</code> with the join result.
     * @since 1.0
     */
    public static String join(double[] array, String seperator)
    {
        if (null == array)
        {
            return null;
        }
        if (null == seperator)
        {
            seperator = "";
        }
        if (0 == array.length)
        {
            return "";
        }
        else
        {
            int current_index = 0;
            String result = "";
            while (current_index < array.length - 1)
            {
                result = result + array[current_index] + seperator;
                current_index++;
            }
            result = result +  array[current_index];
            return result;
        }
    }
    /**
     * Creates a new <code>String</code> object, containing the elements of a
     * supplied array, joined by a given seperator.
     *
     * @param array The float array containing the values to join.
     * @param seperator The seperator used to join the string elements.
     * @return A new <code>String</code> with the join result.
     * @since 1.0
     */
    public static String join(float[] array, String seperator)
    {
        if (null == array)
        {
            return null;
        }
        if (null == seperator)
        {
            seperator = "";
        }
        if (0 == array.length)
        {
            return "";
        }
        else
        {
            int current_index = 0;
            String result = "";
            while (current_index < array.length - 1)
            {
                result = result + array[current_index] + seperator;
                current_index++;
            }
            result = result +  array[current_index];
            return result;
        }
    }
    /**
     * Creates a new <code>String</code> object, containing the elements of a
     * supplied array, joined by a given seperator.
     *
     * @param array The integer array containing the values to join.
     * @param seperator The seperator used to join the string elements.
     * @return A new <code>String</code> with the join result.
     * @since 1.0
     */
    public static String join(int[] array, String seperator)
    {
        if (null == array)
        {
            return null;
        }
        if (null == seperator)
        {
            seperator = "";
        }
        if (0 == array.length)
        {
            return "";
        }
        else
        {
            int current_index = 0;
            String result = "";
            while (current_index < array.length - 1)
            {
                result = result + array[current_index] + seperator;
                current_index++;
            }
            result = result +  array[current_index];
            return result;
        }
    }
    /**
     * Creates a new <code>String</code> object, containing the elements of a
     * supplied array, joined by a given seperator.
     *
     * @param array The long array containing the values to join.
     * @param seperator The seperator used to join the string elements.
     * @return A new <code>String</code> with the join result.
     * @since 1.0
     */
    public static String join(long[] array, String seperator)
    {
        if (null == array)
        {
            return null;
        }
        if (null == seperator)
        {
            seperator = "";
        }
        if (0 == array.length)
        {
            return "";
        }
        else
        {
            int current_index = 0;
            String result = "";
            while (current_index < array.length - 1)
            {
                result = result + array[current_index] + seperator;
                current_index++;
            }
            result = result +  array[current_index];
            return result;
        }
    }
    /**
     * Creates a new <code>String</code> object, containing the elements of a
     * supplied array, joined by a given seperator.
     *
     * @param array The short array containing the values to join.
     * @param seperator The seperator used to join the string elements.
     * @return A new <code>String</code> with the join result.
     * @since 1.0
     */
    public static String join(short[] array, String seperator)
    {
        if (null == array)
        {
            return null;
        }
        if (null == seperator)
        {
            seperator = "";
        }
        if (0 == array.length)
        {
            return "";
        }
        else
        {
            int current_index = 0;
            String result = "";
            while (current_index < array.length - 1)
            {
                result = result + array[current_index] + seperator;
                current_index++;
            }
            result = result +  array[current_index];
            return result;
        }
    }
    /**
     * Creates a new <code>String</code> object, containing the elements of a
     * supplied array, joined by a given seperator.
     *
     * @param array The char array containing the values to join.
     * @param seperator The seperator used to join the string elements.
     * @return A new <code>String</code> with the join result.
     * @since 1.0
     */
    public static String join(char[] array, String seperator)
    {
        return join(array, seperator, null);
    }
    /**
     * Creates a new <code>String</code> object, containing the elements of a
     * supplied array, joined by a given seperator.
     *
     * @param array The char array containing the values to join.
     * @param seperator The seperator used to join the string elements.
     * @param delimiter The delimiter used to surround the string elements.
     * @return A new <code>String</code> with the join result.
     * @since 1.0
     */
    public static String join(char[] array, String seperator, String delimiter)
    {
        if (null == array)
        {
            return null;
        }
        if (null == seperator)
        {
            seperator = "";
        }
        if (null == delimiter)
        {
            delimiter = "";
        }
        if (0 == array.length)
        {
            return "";
        }
        else
        {
            int current_index = 0;
            StringBuilder    result = new StringBuilder();
            while (current_index < array.length - 1)
            {
                result.append(delimiter);
                result.append(array[current_index]);
                result.append(delimiter);
                result.append(seperator);
                current_index++;
            }
            result.append(delimiter);
            result.append(String.valueOf(array[current_index]));
            result.append(delimiter);
            return result.toString();
        }
    }
    /**
     * Returns an array that contains all the occurances of a substring in a
     * string in the correct order. The search will be performed in a
     * case-sensitive manner.
     *
     * @param source The <code>String</code> object that will be searched in.
     * @param substring The string whose occurances will we counted.
     * @return An <code>int[]</code> array containing the indices of the
     * substring.
     * @since 1.0
     */
    public static int[] indicesOf(String source, String substring)
    {
        return indicesOf(source, substring, true);
    }
    /**
     * Returns an array that contains all the occurances of a substring in a
     * string in the correct order.
     *
     * @param source The <code>String</code> object that will be searched in.
     * @param substring The string whose occurances will we counted.
     * @param matchCase A <code>boolean</code> indicating if the match is
     * going to be performed in a case-sensitive manner or not.
     * @return An <code>int[]</code> array containing the indices of the
     * substring.
     * @since 1.0
     */
    public static int[] indicesOf(String source, String substring, boolean matchCase)
    {
        if (null == source ||
            null == substring)
        {
            return new int[0];
        }
        String  source_lookup_reference = null;
        if (!matchCase)
        {
            source_lookup_reference = source.toLowerCase();
            substring = substring.toLowerCase();
        }
        else
        {
            source_lookup_reference = source;
        }
        int current_index = 0;
        int substring_index = 0;
        int count = count(source_lookup_reference, substring);
        int[] indices = new int[count];
        int counter = 0;
        while (current_index < source.length()-1)
        {
            substring_index = source_lookup_reference.indexOf(substring, current_index);
            if (-1 == substring_index)
            {
                break;
            }
            else
            {
                current_index = substring_index + substring.length();
                indices[counter] = substring_index;
                counter++;
            }
        }
        return indices;
    }
    /**
     * Matches a collection of regular expressions against a string.
     *
     * @param value The <code>String</code> that will be checked.
     * @param regexps The collection of regular expressions against which the
     * match will be performed.
     * @return The <code>Matcher</code> instance that corresponds to the
     * <code>String</code> that returned a successful match; or
     * <p><code>null</code> if no match could be found.
     * @since 1.0
     */
    public static Matcher getMatchingRegexp(String value, Collection<Pattern> regexps)
    {
        if (value != null &&
            value.length() > 0 &&
            regexps != null &&
            regexps.size() > 0)
        {
            Matcher matcher = null;
            for (Pattern regexp : regexps)
            {
                matcher = regexp.matcher(value);
                if (matcher.matches())
                {
                    return matcher;
                }
            }
        }
        return null;
    }
    /**
     * Matches a collection of strings against a regular expression.
     *
     * @param values The <code>Collection</code> of <code>String</code>
     * objects that will be checked.
     * @param regexp The regular expression <code>Pattern</code> against which
     * the matches will be performed.
     * @return The <code>Matcher</code> instance that corresponds to the
     * <code>String</code> that returned a successful match; or
     * <p><code>null</code> if no match could be found.
     * @since 1.0
     */
    public static Matcher getRegexpMatch(Collection<String> values, Pattern regexp)
    {
        if (values != null &&
            values.size() > 0 &&
            regexp != null)
        {
            Matcher matcher = null;
            for (String value : values)
            {
                matcher = regexp.matcher(value);
                if (matcher.matches())
                {
                    return matcher;
                }
            }
        }
        return null;
    }
    /**
     * Checks if the name filters through an including and an excluding
     * regular expression.
     *
     * @param name The <code>String</code> that will be filtered.
     * @param included The regular expressions that needs to succeed
     * @param excluded The regular expressions that needs to fail
     * @return <code>true</code> if the name filtered through correctly; or
     * <p><code>false</code> otherwise.
     * @since 1.0
     */
    public static boolean filter(String name, Pattern included, Pattern excluded)
    {
        Pattern[] included_array = null;
        if (included != null)
        {
            included_array = new Pattern[] {included};
        }
        Pattern[] excluded_array = null;
        if (excluded != null)
        {
            excluded_array = new Pattern[] {excluded};
        }
        return filter(name, included_array, excluded_array);
    }
    /**
     * Checks if the name filters through a series of including and excluding
     * regular expressions.
     *
     * @param name The <code>String</code> that will be filtered.
     * @param included An array of regular expressions that need to succeed
     * @param excluded An array of regular expressions that need to fail
     * @return <code>true</code> if the name filtered through correctly; or
     * <p><code>false</code> otherwise.
     * @since 1.0
     */
    public static boolean filter(String name, Pattern[] included, Pattern[] excluded)
    {
        if (null == name)
        {
            return false;
        }
        boolean accepted = false;
        // retain only the includes
        if (null == included)
        {
            accepted = true;
        }
        else
        {
            for (Pattern pattern : included)
            {
                if (pattern != null &&
                    pattern.matcher(name).matches())
                {
                    accepted = true;
                    break;
                }
            }
        }
        // remove the excludes
        if (accepted &&
            excluded != null)
        {
            for (Pattern pattern : excluded)
            {
                if (pattern != null &&
                    pattern.matcher(name).matches())
                {
                    accepted = false;
                    break;
                }
            }
        }
        return accepted;
    }
    /**
     * Ensure that the first character of the provided string is upper case.
     *
     * @param source The <code>String</code> to capitalize.
     * @return The capitalized <code>String</code>.
     * @since 1.0
     */
    public static String capitalize(String source)
    {
        if (source == null || source.length() == 0)
        {
            return source;
        }
        if (source.length() > 1 &&
            Character.isUpperCase(source.charAt(0)))
        {
            return source;
        }
        char chars[] = source.toCharArray();
        chars[0] = Character.toUpperCase(chars[0]);
        return new String(chars);
    }
    /**
     * Ensure that the first character of the provided string lower case.
     *
     * @param source The <code>String</code> to uncapitalize.
     * @return The uncapitalized <code>String</code>.
     * @since 1.5
     */
    public static String uncapitalize(String source)
    {
        if (source == null || source.length() == 0)
        {
            return source;
        }
        if (source.length() > 1 &&
            Character.isLowerCase(source.charAt(0)))
        {
            return source;
        }
        char chars[] = source.toCharArray();
        chars[0] = Character.toLowerCase(chars[0]);
        return new String(chars);
    }
    private static String convertUrl(String source, Pattern pattern, boolean shorten, boolean sanitize, boolean no_follow)
    {
        int max_length = 1024;
        String result = source;
        Matcher url_matcher = pattern.matcher(source);
        boolean found = url_matcher.find();
        if (found)
        {
            String visual_url = null;
            String actual_url = null;
            int last = 0;
            StringBuilder sb = new StringBuilder();
            do
            {
                actual_url = url_matcher.group(1);
                if (url_matcher.groupCount() > 1)
                {
                    visual_url = url_matcher.group(2);
                }
                else
                {
                    visual_url = actual_url;
                }
                if (sanitize)
                {
                    // defang javascript
                    actual_url = StringUtils.replace(actual_url, "javascript:", "");
                    // fill in http:// for URLs that don't begin with /
                    if ((actual_url.indexOf("://") == -1) &&
                        (!actual_url.startsWith("/")))
                    {
                        actual_url = "http://"+actual_url;
                    }
                }
                if (pattern.equals(BBCODE_BAREURL))
                {
                    sb.append(source.substring(last, url_matcher.start(1)));
                }
                else
                {
                    sb.append(source.substring(last, url_matcher.start(0)));
                }
                sb.append("<a href=\"");
                sb.append(actual_url);
                sb.append("\"");
                if (actual_url.startsWith("http://") ||
                    actual_url.startsWith("https://"))
                {
                    sb.append(" target=\"_blank\"");
                }
                if (no_follow)
                {
                    sb.append(" rel=\"nofollow\"");
                }
                sb.append(">");
                if (visual_url.length() <= max_length || !shorten)
                {
                    sb.append(visual_url);
                }
                else
                {
                    String ellipsis = "...";
                    int query_index = visual_url.indexOf("?");
                    // hack query string off
                    // keep '?'
                    if (query_index != -1)
                    {
                        visual_url = visual_url.substring(0, query_index + 1) + ellipsis;
                    }
                    if (visual_url.length() >= max_length)
                    {
                        int last_slash = visual_url.lastIndexOf("/");
                        int start_slash = visual_url.indexOf("/", visual_url.indexOf("://")+3);
                        if (last_slash != start_slash)
                        {
                            visual_url = visual_url.substring(0, start_slash + 1) + ellipsis + visual_url.substring(last_slash);
                        }
                    }
                    sb.append(visual_url);
                }
                sb.append("</a>");
                if (pattern.equals(BBCODE_BAREURL))
                {
                    last = url_matcher.end(1);
                }
                else
                {
                    last = url_matcher.end(0);
                }
                found = url_matcher.find();
            }
            while (found);
            sb.append(source.substring(last));
            result = sb.toString();
        }
        return result;
    }
    private static String parseBBCode(String source, boolean shorten, boolean sanitize, boolean convert_bare, boolean no_follow)
    {
        String result = source;
        result = StringUtils.replace(result, "[b]", "<b>", false);
        result = StringUtils.replace(result, "[/b]", "</b>", false);
        result = StringUtils.replace(result, "[u]", "<u>", false);
        result = StringUtils.replace(result, "[/u]", "</u>", false);
        result = StringUtils.replace(result, "[i]", "<i>", false);
        result = StringUtils.replace(result, "[/i]", "</i>", false);
        result = StringUtils.replace(result, "[pre]", "<pre>", false);
        result = StringUtils.replace(result, "[/pre]", "</pre>", false);
        String            resultCopy = result;
        String            resultLowerCopy = result.toLowerCase();
        StringBuilder    buffer = new StringBuilder();
        int startIndex;
        int endIndex;
        while (-1 != (startIndex = resultLowerCopy.indexOf("[*]")))
        {
            int begin = resultLowerCopy.indexOf("[list]", startIndex + 3);
            int end = resultLowerCopy.indexOf("[/list]", startIndex + 3);
            int next = resultLowerCopy.indexOf("[*]", startIndex + 3); // 3 == sizeof [*]
            if (begin == -1)
            {
                begin = Integer.MAX_VALUE;
            }
            if (end == -1)
            {
                end = Integer.MAX_VALUE;
            }
            if (next == -1)
            {
                next = Integer.MAX_VALUE;
            }
            if (next < begin && next < end)
            {
                endIndex = next;
            }
            else if (begin < next && begin < end)
            {
                endIndex = begin;
            }
            else if (end < next && end < begin)
            {
                endIndex = end;
            }
            else
            {
                endIndex = resultLowerCopy.length();
            }
            buffer
                .append(resultCopy.substring(0, startIndex))
                .append("<li>")
                .append(resultCopy.substring(startIndex + 3, endIndex)) // 3 == sizeof [*]
                .append("</li>");
            resultCopy = resultCopy.substring(endIndex);
            resultLowerCopy = resultLowerCopy.substring(endIndex);
        }
        buffer.append(resultCopy.substring(0));
        result = buffer.toString();
        result = StringUtils.replace(result, "[list]", "<ul>", false);
        result = StringUtils.replace(result, "[/list]", "</ul>", false);
        Matcher color_matcher = BBCODE_COLOR.matcher(result);
        result = color_matcher.replaceAll("<font color=\"$1\">");
        result = StringUtils.replace(result, "[/color]", "</font>", false);
        Matcher size_matcher = BBCODE_SIZE.matcher(result);
        result = size_matcher.replaceAll("<font size=\"$1\">");
        result = StringUtils.replace(result, "[/size]", "</font>", false);
        result = convertUrl(result, BBCODE_URL_SHORT, shorten, sanitize, no_follow);
        result = convertUrl(result, BBCODE_URL_LONG, shorten, sanitize, no_follow);
        if (convert_bare)
        {
            result = convertUrl(result, BBCODE_BAREURL, shorten, sanitize, no_follow);
        }
        Matcher img_matcher = BBCODE_IMG.matcher(result);
        result = img_matcher.replaceAll("<div class=\"bbcode_img\"><img src=\"$1\" border=\"0\" alt=\"\" /></div>");
        Matcher quote_matcher_long = BBCODE_QUOTE_LONG.matcher(result);
        result = quote_matcher_long.replaceAll("<div class=\"quoteaccount\">$1:</div><div class=\"quotebody\">");
        result = StringUtils.replace(result, "[quote]", "<div class=\"quotebody\">", false);
        result = StringUtils.replace(result, "[/quote]", "</div>", false);
        result = StringUtils.replace(result, "\r\n", "<br />\r");
        result = StringUtils.replace(result, "\n", "<br />\n");
        result = StringUtils.replace(result, "\r", "\r\n");
        // remove the BR that could be added due to code formatting ppl
        // use to format lists
        result = StringUtils.replace(result, "ul><br />\r\n", "ul>\r\n");
        result = StringUtils.replace(result, "ul><br />\n", "ul>\n");
        return result;
    }
    /**
     * Converts a <code>String</code> to a <code>boolean</code> value.
     *
     * @param value The <code>String</code> to convert.
     * @return The corresponding <code>boolean</code> value.
     * @since 1.0
     */
    public static boolean convertToBoolean(String value)
    {
        if (null == value)
        {
            return false;
        }
        if (value.equals("1") ||
            value.equalsIgnoreCase("t") ||
            value.equalsIgnoreCase("true") ||
            value.equalsIgnoreCase("y") ||
            value.equalsIgnoreCase("yes") ||
            value.equalsIgnoreCase("on"))
        {
            return true;
        }
        return false;
    }
    /**
     * Converts all tabs on a line to spaces according to the provided tab
     * width.
     *
     * @param line The line whose tabs have to be converted.
     * @param tabWidth The tab width.
     * @return A new <code>String</code> object containing the line with the
     * replaced tabs.
     * @since 1.0
     */
    public static String convertTabsToSpaces(String line, int tabWidth)
    {
        StringBuilder result = new StringBuilder();
        int tab_index = -1;
        int last_tab_index = 0;
        int added_chars = 0;
        int tab_size;
        while ((tab_index = line.indexOf("\t", last_tab_index)) != -1)
        {
            tab_size = tabWidth-((tab_index+added_chars)%tabWidth);
            if (0 == tab_size)
            {
                tab_size = tabWidth;
            }
            added_chars += tab_size-1;
            result.append(line.substring(last_tab_index, tab_index));
            result.append(StringUtils.repeat(" ", tab_size));
            last_tab_index = tab_index+1;
        }
        if (0 == last_tab_index)
        {
            return line;
        }
        else
        {
            result.append(line.substring(last_tab_index));
        }
        return result.toString();
    }
    /**
     * Ensures that all whitespace is removed from a <code>String</code>.
     * <p>It also works with a <code>null</code> argument.
     *
     * @param source The <code>String</code> to trim.
     * @return The trimmed <code>String</code>.
     * @since 1.0
     */
    public static String trim(String source)
    {
        if (source == null || source.length() == 0)
        {
            return source;
        }
        return source.trim();
    }
    /**
     * Reformats a string where lines that are longer than <tt>width</tt>
     * are split apart at the earliest wordbreak or at maxLength, whichever is
     * sooner. If the width specified is less than 5 or greater than the input
     * Strings length the string will be returned as is.
     * <p>
     * Please note that this method can be lossy - trailing spaces on wrapped
     * lines may be trimmed.
     *
     * @param input the String to reformat.
     * @param width the maximum length of any one line.
     * @return a new String with reformatted as needed.
     */
    public static String wordWrap(String input, int width, Locale locale)
    {
        // handle invalid input
        if (input == null)
        {
            return "";
        }
        else if (width < 5)
        {
            return input;
        }
        else if (width >= input.length())
        {
            return input;
        }
        // default locale
        if (locale == null)
        {
            locale = Locale.US;
        }
        StringBuilder buffer = new StringBuilder(input.length());
        int        current_index = 0;
        int        delimiter_index = 0;
        String    seperator = "\n";
        String    line;
        // go over the input string and jump from line to line
        while (current_index <= input.length())
        {
            // look for the next linebreak
            delimiter_index = input.indexOf(seperator, current_index);
            // get the line that corresponds to it
            if (-1 == delimiter_index)
            {
                line = new String(input.substring(current_index, input.length()));
                current_index = input.length() + 1;
            }
            else
            {
                line = new String(input.substring(current_index, delimiter_index));
                current_index = delimiter_index + seperator.length();
            }
            // handle the wrapping of the line
            BreakIterator breaks = BreakIterator.getLineInstance(locale);
            breaks.setText(line);
            int line_start = 0;
            int start = breaks.first();
            int end = breaks.next();
            while (end != BreakIterator.DONE)
            {
                // check if the width has been exceeded
                if (end - 1 - line_start >= width)
                {
                    boolean break_line = true;
                    // first check if the last characters were spaces,
                    // if they were and by removing them the width is not
                    // exceeded, just continue
                    if (Character.isWhitespace(line.charAt(end - 1)))
                    {
                        for (int j = end - 1; j >= 0; j--)
                        {
                            if (!Character.isWhitespace(line.charAt(j)))
                            {
                                if (j - line_start < width)
                                {
                                    break_line = false;
                                }
                                break;
                            }
                        }
                    }
                    if (break_line)
                    {
                        String line_breaked = line.substring(line_start, start);
                        // this can happen with trailing whitespace
                        if (line_breaked.length() > width)
                        {
                            line_breaked = line_breaked.substring(0, width);
                        }
                        buffer.append(line_breaked);
                        buffer.append("\n");
                        line_start = start;
                    }
                }
                start = end;
                end = breaks.next();
            }
            if (line_start < line.length())
            {
                buffer.append(line.substring(line_start));
            }
            if (delimiter_index != -1)
            {
                buffer.append("\n");
            }
        }
        return buffer.toString();
    }
}
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TPCLIDConverter.java
New file
@@ -0,0 +1,758 @@
package com.ximple.eofms.util;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
public abstract class TPCLIDConverter
{
    private final static int SX1200 = 800;
    private final static int SY1200 = 500;
    public static String CoordinateToTpclId(Coordinate dp)
    {
        long orgX, orgY;
        int mapX, mapY;
        int shiftX, shiftY;
        int dx1, dy1;
        int dx2, dy2;
        if (dp == null)
        {
            return null;
        }
        double X = dp.x;
        double Y = dp.y;
        String CoordToTPCLID = "";
        char mapID = CoordinateToSingleMapID(dp);
        if (mapID == 'w')
        {
            return "";
        }
        /* get the origin point of mapID */
        Coordinate Point = getOriginPoint("" + mapID, Integer.MAX_VALUE);
        if (Point == null)
        {
            return null;
        }
        orgX = (long) Point.x;
        orgY = (long) Point.y;
        mapX = intDivision((X - orgX), SX1200);
        if (mapID == 'Z' && mapX >= 100)
        {
            mapX = mapX - 100;
        }
        mapY = intDivision((Y - orgY), SY1200);
        shiftX = (int) (X - orgX) % SX1200;
        shiftY = (int) (Y - orgY) % SY1200;
        dx1 = intDivision((shiftX % 100), 10);
        dy1 = intDivision((shiftY % 100), 10);
        dx2 = (shiftX % 100) % 10;
        dy2 = (shiftY % 100) % 10;
        CoordToTPCLID = "" + mapID;
        CoordToTPCLID = CoordToTPCLID + dataFormat(mapX);
        CoordToTPCLID = CoordToTPCLID + dataFormat(mapY);
        CoordToTPCLID = CoordToTPCLID + intToAscii(shiftX / 100 + asciiToInt("A"));
        CoordToTPCLID = CoordToTPCLID + intToAscii(shiftY / 100 + asciiToInt("A"));
        CoordToTPCLID = CoordToTPCLID + dx1 + dy1 + dx2 + dy2;
        return CoordToTPCLID;
    }
    public static char CoordinateToSingleMapID(Coordinate dp)
    {
        char mapID = 'w';
        String[] strY = StringUtils.splitToArray(Double.toString(dp.y), ".");
        String[] strX = StringUtils.splitToArray(Double.toString(dp.x), ".");
        int intY = Integer.parseInt(strY[0]);
        int intX = Integer.parseInt(strX[0]);
        if (intY > 2944000)
        {
            return mapID;
        }
        if (intY >= 2894000 && intY <= 2944000 && intX >= 10000 && intX <= 90000)
        {
            mapID = 'S';
            return mapID;
        }
        if (intY >= 2614000 && intY <= 2664000 && intX >= 10000 && intX <= 66000)
        {
            mapID = 'X';
            return mapID;
        }
        if (intY >= 2564000 && intY <= 2614000 && intX >= 10000 && intX <= 66000)
        {
            mapID = 'Y';
            return mapID;
        }
        if (intY >= 2675800 && intY <= 2725800 && intX >= 10000 && intX <= 170000)
        {
            mapID = 'Z';
            return mapID;
        }
        if (intY > 2800000)
        {
            return mapID;
        }
        if (intY >= 2750000)
        {
            if (intX < 170000)
            {
                return mapID;
            }
            if (intX < 250000)
            {
                mapID = 'A';
                return mapID;
            }
            if (intX < 330000)
            {
                mapID = 'B';
                return mapID;
            }
            if (intX < 410000)
            {
                mapID = 'C';
                return mapID;
            }
            return mapID;
        }
        if (intY >= 2700000)
        {
            if (intX < 170000)
            {
                return mapID;
            }
            if (intX < 250000)
            {
                mapID = 'D';
                return mapID;
            }
            if (intX < 330000)
            {
                mapID = 'E';
                return mapID;
            }
            if (intX < 410000)
            {
                mapID = 'F';
                return mapID;
            }
            return mapID;
        }
        if (intY >= 2650000)
        {
            if (intX < 170000)
            {
                return mapID;
            }
            if (intX < 250000)
            {
                mapID = 'G';
                return mapID;
            }
            if (intX < 330000)
            {
                mapID = 'H';
                return mapID;
            }
            if (intX < 410000)
            {
                mapID = 'I';
                return mapID;
            }
            return mapID;
        }
        if (intY >= 2600000)
        {
            if (intX < 90000)
            {
                return mapID;
            }
            if (intX < 170000)
            {
                mapID = 'J';
                return mapID;
            }
            if (intX < 250000)
            {
                mapID = 'K';
                return mapID;
            }
            if (intX < 330000)
            {
                mapID = 'L';
                return mapID;
            }
            return mapID;
        }
        if (intY >= 2550000)
        {
            if (intX < 90000)
            {
                return mapID;
            }
            if (intX < 170000)
            {
                mapID = 'M';
                return mapID;
            }
            if (intX < 250000)
            {
                mapID = 'N';
                return mapID;
            }
            if (intX < 330000)
            {
                mapID = 'O';
                return mapID;
            }
            return mapID;
        }
        if (intY >= 2500000)
        {
            if (intX < 90000)
            {
                return mapID;
            }
            if (intX < 170000)
            {
                mapID = 'P';
                return mapID;
            }
            if (intX < 250000)
            {
                mapID = 'Q';
                return mapID;
            }
            if (intX < 330000)
            {
                mapID = 'R';
                return mapID;
            }
            return mapID;
        }
        if (intY >= 2450000)
        {
            if (intX < 90000)
            {
                return mapID;
            }
            if (intX < 170000)
            {
                mapID = 'S';
                return mapID;
            }
            if (intX < 250000)
            {
                mapID = 'T';
                return mapID;
            }
            if (intX < 330000)
            {
                mapID = 'U';
                return mapID;
            }
            return mapID;
        }
        if (intY >= 2400000)
        {
            if (intX < 170000)
            {
                return mapID;
            }
            if (intX < 250000)
            {
                mapID = 'V';
                return mapID;
            }
            if (intX < 330000)
            {
                mapID = 'W';
                return mapID;
            }
            return mapID;
        }
        return mapID;
    }
    public static Envelope convertTpclIdToEnvelope(String tpclid)
    {
        String tempString = "";
        Coordinate point = null;
        Coordinate tempPoint = null;
        double width, height;
        if (tpclid.length() < 5)
        {
            return null;
        }
        tempString = tpclid.substring(0, 1);
        int xmapid = Integer.parseInt(tpclid.substring(1, 2));
        // Get the origin point
        point = getOriginPoint(tempString, xmapid);
        if (point == null)
        {
            return null;
        }
        tempString = tpclid.substring(1, 4);
        width = SX1200;
        height = SY1200;
        tempPoint = twoNumberScale(tempString, 800, 500);
        if (tempPoint != null)
        {
            point.x = (point.x + tempPoint.x);
            point.y = (point.y + tempPoint.y);
        }
        if (tpclid.length() >= 7)
        {
            tempString = (asciiToInt(tpclid.substring(5, 1)) - 65) + "" + (asciiToInt(tpclid.substring(6, 1)) - 65);
            tempPoint = twoNumberScale(tempString, 100);
            if (tempPoint != null)
            {
                point.x = point.x + tempPoint.x;
                point.y = point.y + tempPoint.y;
            }
            width = 100.0;
            height = 100.0;
        }
        if (tpclid.length() >= 9)
        {
            tempString = tpclid.substring(7, 2);
            tempPoint = twoNumberScale(tempString, 10);
            if (tempPoint != null)
            {
                point.x = point.x + tempPoint.x;
                point.y = point.y + tempPoint.y;
            }
            width = 10.0;
            height = 10.0;
        }
        if (tpclid.length() >= 11)
        {
            tempString = tpclid.substring(9);
            tempPoint = twoNumberScale(tempString, 1);
            if (tempPoint != null)
            {
                point.x = point.x + tempPoint.x;
                point.y = point.y + tempPoint.y;
            }
            width = 1.0;
            height = 1.0;
        }
        Coordinate pt2 = new Coordinate(point);
        pt2.x += width;
        pt2.y += height;
        return  new Envelope(point, pt2);
    }
    public static Coordinate convertTpclIdToCoordinate(String tpclid)
    {
        String tempString = "";
        Coordinate point = null;
        Coordinate tempPoint = null;
        if (tpclid.length() < 5)
        {
            return null;
        }
        tempString = tpclid.substring(0, 1);
        int xmapid = Integer.parseInt(tpclid.substring(1, 2));
        // Get the origin point
        point = getOriginPoint(tempString, xmapid);
        if (point == null)
        {
            return null;
        }
        tempString = tpclid.substring(1, 4);
        tempPoint = twoNumberScale(tempString, 800, 500);
        if (tempPoint != null)
        {
            point.x = (point.x + tempPoint.x);
            point.y = (point.y + tempPoint.y);
        }
        if (tpclid.length() >= 7)
        {
            tempString = (asciiToInt(tpclid.substring(5, 1)) - 65) + "" + (asciiToInt(tpclid.substring(6, 1)) - 65);
            tempPoint = twoNumberScale(tempString, 100);
            if (tempPoint != null)
            {
                point.x = point.x + tempPoint.x;
                point.y = point.y + tempPoint.y;
            }
        }
        if (tpclid.length() >= 9)
        {
            tempString = tpclid.substring(7, 2);
            tempPoint = twoNumberScale(tempString, 10);
            if (tempPoint != null)
            {
                point.x = point.x + tempPoint.x;
                point.y = point.y + tempPoint.y;
            }
        }
        if (tpclid.length() >= 11)
        {
            tempString = tpclid.substring(9);
            tempPoint = twoNumberScale(tempString, 1);
            if (tempPoint != null)
            {
                point.x = point.x + tempPoint.x;
                point.y = point.y + tempPoint.y;
            }
        }
        return point;
    }
    private static int intDivision(double p1, int p2)
    {
        double resultValue = 0.0;
        String result;
        resultValue = p1 / p2;
        result = Double.toString(resultValue);
        String[] temp = StringUtils.splitToArray(result, ".");
        result = temp[0];
        return Integer.parseInt(result);
    }
    private static Coordinate twoNumberScale(String number, int scaleX, int scaleY)
    {
        Coordinate tempPoint = new Coordinate();
        if (number.length() == 2)
        {
            tempPoint.x = Double.parseDouble(number.substring(0, 1)) * scaleX;
            tempPoint.y = Double.parseDouble(number.substring(1, 1)) * scaleY;
        } else if (number.length() == 1)
        {
            tempPoint.x = Double.parseDouble(number.substring(0, 1)) * scaleX;
            tempPoint.y = 0;
        } else if (number.length() == 4)
        {
            tempPoint.x = Double.parseDouble(number.substring(0, 2)) * scaleX;
            tempPoint.y = Double.parseDouble(number.substring(2, 2)) * scaleY;
        } else
        {
            tempPoint.x = 0;
            tempPoint.y = 0;
        }
        return tempPoint;
    }
    private static int asciiToInt(String p1)
    {
        if (p1.endsWith("A")) return 65;
        if (p1.endsWith("B")) return 66;
        if (p1.endsWith("C")) return 67;
        if (p1.endsWith("D")) return 68;
        if (p1.endsWith("E")) return 69;
        if (p1.endsWith("F")) return 70;
        if (p1.endsWith("G")) return 71;
        if (p1.endsWith("H")) return 72;
        if (p1.endsWith("I")) return 73;
        if (p1.endsWith("J")) return 74;
        if (p1.endsWith("K")) return 75;
        if (p1.endsWith("L")) return 76;
        if (p1.endsWith("M")) return 77;
        if (p1.endsWith("N")) return 78;
        if (p1.endsWith("O")) return 79;
        if (p1.endsWith("P")) return 80;
        if (p1.endsWith("Q")) return 81;
        if (p1.endsWith("R")) return 82;
        if (p1.endsWith("S")) return 83;
        if (p1.endsWith("T")) return 84;
        if (p1.endsWith("U")) return 85;
        if (p1.endsWith("V")) return 86;
        if (p1.endsWith("W")) return 87;
        if (p1.endsWith("X")) return 88;
        if (p1.endsWith("Y")) return 89;
        if (p1.endsWith("Z")) return 90;
        return 0;
    }
    private static char intToAscii(int p1)
    {
        switch (p1)
        {
        case 65:
            return 'A';
        case 66:
            return 'B';
        case 67:
            return 'C';
        case 68:
            return 'D';
        case 69:
            return 'E';
        case 70:
            return 'F';
        case 71:
            return 'G';
        case 72:
            return 'H';
        case 73:
            return 'I';
        case 74:
            return 'J';
        case 75:
            return 'K';
        case 76:
            return 'L';
        case 77:
            return 'M';
        case 78:
            return 'N';
        case 79:
            return 'O';
        case 80:
            return 'P';
        case 81:
            return 'Q';
        case 82:
            return 'R';
        case 83:
            return 'S';
        case 84:
            return 'T';
        case 85:
            return 'U';
        case 86:
            return 'V';
        case 87:
            return 'W';
        case 88:
            return 'X';
        case 89:
            return 'Y';
        case 90:
            return 'Z';
        default:
            return '1';
        }
    }
    private static Coordinate getOriginPoint(String letter, int xMapId)
    {
        int aSwitch = asciiToInt(letter);
        Coordinate Point = new Coordinate();
        switch (aSwitch)
        {
        case 65: //A
        {
            Point.x = 170000;
            Point.y = 2750000;
            break;
        }
        case 66: //B
        {
            Point.x = 250000;
            Point.y = 2750000;
            break;
        }
        case 67: //C
        {
            Point.x = 330000;
            Point.y = 2750000;
            break;
        }
        case 68: //D
        {
            Point.x = 170000;
            Point.y = 2700000;
            break;
        }
        case 69: //E
        {
            Point.x = 250000;
            Point.y = 2700000;
            break;
        }
        case 70: //F
        {
            Point.x = 330000;
            Point.y = 2700000;
            break;
        }
        case 71: //G
        {
            Point.x = 170000;
            Point.y = 2650000;
            break;
        }
        case 72: //H
        {
            Point.x = 250000;
            Point.y = 2650000;
            break;
        }
        case 73: //I
        {
            Point.x = 330000;
            Point.y = 2650000;
            break;
        }
        case 74: //J
        {
            Point.x = 90000;
            Point.y = 2600000;
            break;
        }
        case 75: //K
        {
            Point.x = 170000;
            Point.y = 2600000;
            break;
        }
        case 76: //L
        {
            Point.x = 250000;
            Point.y = 2600000;
            break;
        }
        case 77: //M
        {
            Point.x = 90000;
            Point.y = 2550000;
            break;
        }
        case 78: //N
        {
            Point.x = 170000;
            Point.y = 2550000;
            break;
        }
        case 79: //O
        {
            Point.x = 250000;
            Point.y = 2550000;
            break;
        }
        case 80: //P
        {
            Point.x = 90000;
            Point.y = 2500000;
            break;
        }
        case 81: //Q
        {
            Point.x = 170000;
            Point.y = 2500000;
            break;
        }
        case 82: //R
        {
            Point.x = 250000;
            Point.y = 2500000;
            break;
        }
        case 83: //°¨¯ª S
        {
            Point.x = 10000;
            Point.y = 2894000;
            break;
        }
        case 84: //T
        {
            Point.x = 170000;
            Point.y = 2450000;
            break;
        }
        case 85: //U
        {
            Point.x = 250000;
            Point.y = 2450000;
            break;
        }
        case 86: //V
        {
            Point.x = 170000;
            Point.y = 2400000;
            break;
        }
        case 87: // W
        {
            Point.x = 250000;
            Point.y = 2400000;
            break;
        }
        case 88: //¼ê´ò X
        {
            Point.x = 10000;
            Point.y = 2614000;
            break;
        }
        case 89: //¼ê´ò Y
        {
            Point.x = 10000;
            Point.y = 2564000;
            break;
        }
        case 90: //ª÷ªù ¥ªZ
        {
            Point.x = (xMapId < 51) ? 90000 : 10000;
            Point.y = 2675800;
            break;
        }
        default:
        {
            return null;
        }
        }
        return Point;
    }
    private static Coordinate twoNumberScale(String number, int scale)
    {
        return twoNumberScale(number, scale, scale);
    }
    private static String dataFormat(int p1)
    {
        String s1 = Integer.toString(p1);
        if (s1.length() < 2)
            s1 = "0" + s1;
        return s1;
    }
}
xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java
@@ -9,7 +9,7 @@
 * Time: ¤U¤È 01:35:03
 * To change this template use File | Settings | File Templates.
 */
public class TWDDatumConverter
public abstract class TWDDatumConverter
{
    /*
     *   Definition of math related value
@@ -490,8 +490,13 @@
     * }
     */
    /**
     * ¥ÑTM2®y¼ÐÂà´«¦ÜTWD97®y¼Ð
     * @param pt TM2¦ì¸m
     * @return ·sªºTWD97®y¼Ð
     */
    public static Coordinate fromTM2ToTWD97(Coordinate pt)
    {
         return  fromTM2(TWD97_A,TWD97_ECC,TWD97_ECC2, 0, 121, TWD97_TM2, pt.x, pt.y);
         return  fromTM2(TWD97_A,TWD97_ECC,TWD97_ECC2, 0, 121, TWD97_TM2, pt.x - 250000.0, pt.y);
    }
}