src.openwfe.org.decision.impl.CsvDecisionTableFactory Maven / Gradle / Ivy
/*
* Copyright (c) 2006, John Mettraux, OpenWFE.org
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* . Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* . Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* . Neither the name of the "OpenWFE" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $Id: AbstractService.java 2587 2006-05-09 09:15:59Z jmettraux $
*/
//
// CsvDecisionTableFactory.java
//
// [email protected]
//
// generated with
// jtmpl 1.1.01 2004/05/19 ([email protected])
//
package openwfe.org.decision.impl;
import openwfe.org.Utils;
import openwfe.org.MapUtils;
import openwfe.org.decision.DecisionTable;
import openwfe.org.decision.DecisionException;
import openwfe.org.decision.DecisionTableFactory;
/**
* Turning CSV files into decision tables.
*
* CVS Info :
*
$Author$
*
$Id$
*
* @author [email protected]
*/
public class CsvDecisionTableFactory
extends FileDecisionTableFactory
{
private final static org.apache.log4j.Logger log = org.apache.log4j.Logger
.getLogger(CsvDecisionTableFactory.class.getName());
//
// CONSTANTS & co
/**
* Cells whose value begin with 'in:' are indicating which fields
* should be used for the rule evaluation.
*/
public final static String IN_PREFIX
= "in:";
/**
* Cells whose value begin with 'out:' are telling which fields should
* receive potential output.
*/
public final static String OUT_PREFIX
= "out:";
/**
* 'option:', lines coming before the header row (where in: and out: are
* used), may comprise rows whose first cell is an option.
*/
public final static String OPTION_PREFIX
= "option:";
/**
* When the option 'through' is set, every rule (row) in the table will
* be evaluated. When it's not set (the default), as soon as a rule
* matches, its consequences are applied and the 'decision' is over.
*/
public final static String OPT_THROUGH
= "through";
/**
* When this 'ignorecase' option is set, the regex matching of the field
* totally ignores the case for the rules and the actual workitem values.
*/
public final static String OPT_IGNORECASE
= "ignorecase";
//
// FIELDS
//
// CONSTRUCTORS
/**
* Given a set of parameters, readies the factory for a later call
* to buildTables().
*/
public void init (final java.util.Map parameters)
throws DecisionException
{
super.init(parameters);
}
//
// METHODS from DecisionTableFactory
/**
* Actually loads the table.
* getTable() shall call this method.
*/
public DecisionTable loadTable (final String tableName)
throws DecisionException
{
return loadTableDirectly(this.getTableUrl(tableName));
}
//
// METHODS
/**
* Loads a table directly from a URL; useful for testing decision tables.
*/
public DecisionTable loadTableDirectly (final String tableUrl)
throws DecisionException
{
try
{
final java.net.URLConnection con =
(new java.net.URL(tableUrl)).openConnection();
final java.io.InputStream is = con.getInputStream();
final java.io.BufferedReader br =
new java.io.BufferedReader(new java.io.InputStreamReader(is));
return loadTable(br);
}
catch (final DecisionException e)
{
throw e;
}
catch (final Throwable t)
{
throw new DecisionException
("failed to load table at "+tableUrl, t);
}
}
/**
* The bulk job of table building is gathered in this method.
*/
protected DecisionTable loadTable (final java.io.BufferedReader br)
throws DecisionException, java.io.IOException
{
boolean headerParsed = false;
final java.util.List ins = new java.util.ArrayList(20);
final java.util.List outs = new java.util.ArrayList(20);
final java.util.List rows = new java.util.ArrayList(100);
final SimpleDecisionTable table = new SimpleDecisionTable();
while (true)
{
final String row = br.readLine();
if (row == null) break;
if (log.isDebugEnabled())
log.debug("loadTable() \n"+row);
final java.util.List cells = csvSplit(row);
/*
if (log.isDebugEnabled())
{
log.debug("loadTable() found "+cells.size()+" cells");
for (int i=0; i"+cells.get(i)+"<");
}
*/
if (cells.size() < 1)
throw new DecisionException("no cells, cannot load table");
if (headerParsed)
{
expandEmptyCells(cells);
final String[] rins = new String[ins.size()];
final String[] routs = new String[outs.size()];
final java.util.Iterator it = cells.iterator();
for (int i=0; i"+rins[i]+"<");
}
for (int i=0; i"+routs[i]+"<");
}
if (notEmpty(rins) || notEmpty(routs))
{
log.debug("loadTable() adding row");
rows.add(new String[][] { rins, routs });
}
continue;
}
//
// is there a configuration option ?
if (cells.size() > 0 &&
((String)cells.get(0)).startsWith(OPTION_PREFIX))
{
evalOptions(table, cells);
continue;
}
if ( ! isHeaderRow(cells)) continue;
//
// parse headers
int i = 0;
//
// parse in:
while (true)
{
String s = (String)cells.get(i);
if (s.startsWith(OUT_PREFIX)) break;
s = s.substring(IN_PREFIX.length());
ins.add(s);
i++;
log.debug("loadTable() in : >"+s+"<");
}
//
// parse out:
while (true)
{
if (i >= cells.size()) break;
String s = (String)cells.get(i);
s = s.substring(OUT_PREFIX.length());
outs.add(s);
i++;
log.debug("loadTable() out : >"+s+"<");
}
//
// done
headerParsed = true;
}
table.setIns(ins);
table.setOuts(outs);
table.setRows(rows);
return table;
}
private boolean notEmpty (final String[] ss)
{
for (int i=0; i 0) return true;
return false;
}
private boolean isHeaderRow (final java.util.List cells)
{
final java.util.Iterator it = cells.iterator();
while (it.hasNext())
{
final String s = (String)it.next();
//log.debug("isHeaderRow() >"+s+"<");
if (( ! s.startsWith(IN_PREFIX)) &&
( ! s.startsWith(OUT_PREFIX)))
{
return false;
}
}
return true;
}
/**
* Evalutation of the rows coming before the header row.
*/
protected void evalOptions
(final SimpleDecisionTable table,
final java.util.List cells)
{
final java.util.Iterator it = cells.iterator();
while (it.hasNext())
{
String s = (String)it.next();
if ( ! s.startsWith(OPTION_PREFIX)) continue;
s = s.substring(OPTION_PREFIX.length());
int i = s.indexOf(",");
if (i > -1) s = s.substring(0, i);
if (log.isDebugEnabled())
log.debug("evalOptions() >"+s+"<");
if (OPT_THROUGH.equalsIgnoreCase(s)) table.setFirstMatch(false);
if (OPT_IGNORECASE.equalsIgnoreCase(s)) table.setIgnoreCase(true);
}
}
//
// STATIC METHODS
private static java.util.regex.Pattern csvPat =
// java.util.regex.Pattern.compile("([0-9]|\"),([0-9]|\")");
// java.util.regex.Pattern.compile("(-?[0-9]|\"|,),(-?[0-9]|\")");
java.util.regex.Pattern.compile("([\\-0-9]|\"|,),([\\-0-9]|\")");
//
// works with rows like "a",,"c"
private static String polish (final String s)
{
return s
.replaceFirst("\"(.*)\"", "$1")
.replaceAll("\"\"", "\"");
}
/**
* This method splits a CSV line into a list of Strings. It's available
* as public and static, as other classes may perhaps need it.
*/
public static java.util.List csvSplit (String s)
{
if (s.endsWith(",")) s = s + "\"\"";
if (s.startsWith(",")) s = "\"\"" + s;
//
// two dirty hacks... A better regex would be welcome
final java.util.List result = new java.util.ArrayList(30);
final java.util.regex.Matcher matcher = csvPat.matcher(s);
int i = 0;
while (matcher.find(i))
{
result.add(polish(s.substring(i, matcher.end(1))));
i = matcher.end(2) - 1;
}
result.add(polish(s.substring(i)));
//if (s.endsWith(",")) result.add("");
return result;
}
/*
* a bit of polishing again...
*/
private static void expandEmptyCells (final java.util.List l)
{
final java.util.List result = new java.util.ArrayList(l);
java.util.Collections.reverse(result);
l.clear();
final java.util.Iterator it = result.iterator();
while (it.hasNext())
{
String s = (String)it.next();
//if (log.isDebugEnabled())
// log.debug("expandEmptyCells() s is >"+s+"<");
while (s.endsWith(","))
{
l.add(0, "");
s = s.substring(0, s.length()-1);
}
l.add(0, s);
}
}
//
// INNER CLASSES
}