All Downloads are FREE. Search and download functionalities are using the official Maven repository.

at.newmedialab.ldpath.model.backend.AbstractBackend Maven / Gradle / Ivy

package at.newmedialab.ldpath.model.backend;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import at.newmedialab.ldpath.api.backend.RDFBackend;
import at.newmedialab.ldpath.util.FormatUtils;


/**
 * This provides an generic implementation of all **Value(Node node) 
 * methods other than {@link #stringValue(Object)}.

* This allows to implement {@link RDFBackend}s without dealing with the actual * conversions needed for types literals not directly supported by a backend.

* Backends however should implement - override default implementations provided * by this class - **Value(Node node) methods with natively supported * types to avoid unnecessary type conversions. *

* An Example for a RDFRepository<Object> that directly uses the the * Java types for typed literals as nodes. *

 *     public Double doubleValue(Object node) {
 *         //assume that this is typically only called on Double values
 *         try { 
 *             return (Double)node;
 *         } catch (ClassCastException e){
 *             //not a Double - call super to trigger parsing from
 *             //the lexical form.
 *             return super.doubleValue(node);
 *         }
 * 
* Here an other possible implementation that does not assume that the node is * of the requested type. *
 *     public Double doubleValue(Object node) {
 *         if(node instanceof Double){
 *             return (Double)node;
 *         } else {
 *             //not a Double - call super to trigger parsing from
 *             //the lexical form.
 *             return super.doubleValue(node);
 *         }
 * 
* It will depend on the use cases what of the two implementations performs * better. * @see at.newmedialab.ldpath.api.backend.RDFBackend#stringValue(java.lang.Object) */ public abstract class AbstractBackend implements RDFBackend { /** * A clone of the DateFormat provided by {@link FormatUtils} to parse xsd:date * values. This is necessary because {@link SimpleDateFormat} is not thread * save and therefore we do not directly use a public static member. */ private SimpleDateFormat dateFormat = (SimpleDateFormat)FormatUtils.ISO8601FORMAT_DATE.clone(); /** * A clone of the DateFormat provided by {@link FormatUtils} to parse xsd:time * values. This is necessary because {@link SimpleDateFormat} is not thread * save and therefore we do not directly use a public static member. */ private SimpleDateFormat timeFormat = (SimpleDateFormat)FormatUtils.ISO8601FORMAT_TIME.clone(); /** * Parses the Double value of the parsed node based on its lexical form as * returned by {@link #stringValue(Object)}. * @return the double value * @throws NumberFormatException if the lexical form can not be converted * to a Double. * @see at.newmedialab.ldpath.api.backend.RDFBackend#doubleValue(java.lang.Object) */ @Override public Double doubleValue(Node node) { return new Double(trimPlusSign(stringValue(node))); } /** * Parses the Float value of the parsed node based on its lexical form as * returned by {@link #stringValue(Object)}. * @return the float value * @throws NumberFormatException if the lexical form can not be converted * to a Double. * @see at.newmedialab.ldpath.api.backend.RDFBackend#floatValue(java.lang.Object) */ public Float floatValue(Node node) { return new Float(trimPlusSign(stringValue(node))); }; /** * Parses the {@link BigDecimal#longValueExact() Long value} of the parsed * node by using {@link #decimalValue(Object)}. This has the advantage, that * decimal values that are also valid long values - such as '1.0' are also * correctly converted to long.

* @return the long value * @throws NumberFormatException if the lexical form can not be converted * to an Long. * @throws ArithmeticException if the lexical form can not be converted * to a Long. * @see at.newmedialab.ldpath.api.backend.RDFBackend#longValue(java.lang.Object) */ @Override public Long longValue(Node node) { return decimalValue(node).longValueExact(); } /** * Parses the {@link BigDecimal#intValueExact() Integer value} of the parsed * node by using {@link #decimalValue(Object)}. This has the advantage, that * decimal values that are also valid integer values - such as '1.0' are also * correctly converted to {@link Integer}.

* @return the int value * @throws NumberFormatException if the lexical form can not be converted * to an Long. * @throws ArithmeticException if the lexical form can not be converted * to a Long. * @see at.newmedialab.ldpath.api.backend.RDFBackend#intValue(java.lang.Object) */ @Override public Integer intValue(Node node) { return decimalValue(node).intValueExact(); }; /** * Parses the {@link BigDecimal} value from the lexical form of the parsed * node as returned by {@link RDFBackend#stringValue(Object)}. This * trims loading '+' sings. * @return the int value * @throws NumberFormatException if the lexical form can not be converted * to an Long. * @throws ArithmeticException if the lexical form can not be converted * to a Long. * @see at.newmedialab.ldpath.api.backend.RDFBackend#decimalValue(java.lang.Object) */ public BigDecimal decimalValue(Node node) { return new BigDecimal(trimPlusSign(stringValue(node))); }; /** * Parses the {@link BigDecimal#toBigIntegerExact() BugIneger value} of the parsed * node by using {@link #decimalValue(Object)}. This has the advantage, that * decimal values that are also valid integer values - such as '1.0' are also * correctly converted to {@link BigInteger}.

* @see at.newmedialab.ldpath.api.backend.RDFBackend#integerValue(java.lang.Object) */ public java.math.BigInteger integerValue(Node node) { return decimalValue(node).toBigIntegerExact(); }; /** * Parses the boolean value from the {@link #stringValue(Object) lexical form}. * Supports both '1' and {@link Boolean#parseBoolean(String)}. * @return the boolean value * @see at.newmedialab.ldpath.api.backend.RDFBackend#booleanValue(java.lang.Object) */ public Boolean booleanValue(Node node) { String lexicalForm = stringValue(node); if(lexicalForm.length() == 1){ //support '1' as true return lexicalForm.charAt(0) == '1'; } else { return Boolean.parseBoolean(lexicalForm); } }; /** * Parses date vales based on the ISO8601 specification by using the * {@link #stringValue(Object) lexical form} of the parsed node. * @return the {@link Date} representing the parsed date. * @throws IllegalArgumentException on any {@link ParseException} while * parsing the {@link #stringValue(Object) lexical form} of the parsed * node. * @see at.newmedialab.ldpath.api.backend.RDFBackend#dateValue(java.lang.Object) */ public Date dateValue(Node node) { String lexicalForm = stringValue(node); try { return parseDate(lexicalForm); } catch (ParseException e) { throw new IllegalArgumentException("could not parse ISO8601 date from '"+ lexicalForm+"'!",e); } }; /** * Parses time value based on the ISO8601 specification by using the * {@link #stringValue(Object) lexical form} of the parsed node. * @return the {@link Date} representing the parsed date. * @throws IllegalArgumentException on any {@link ParseException} while * parsing the {@link #stringValue(Object) lexical form} of the parsed * node. * @see at.newmedialab.ldpath.api.backend.RDFBackend#timeValue(java.lang.Object) */ public Date timeValue(Node node) { String lexicalForm = stringValue(node); try { return parseTime(lexicalForm); } catch (ParseException e) { throw new IllegalArgumentException("could not parse ISO8601 time from '"+ lexicalForm+"'!",e); } }; /** * Parses dateTime value based on the {@link #stringValue(Object) lexical form} * of the parsed node. For details about parsing see * {@link FormatUtils#parseDate(String)}. * @return the {@link Date} representing the parsed date. * @throws IllegalArgumentException if the parsed node can not be converted * to an {@link Date}. * @see at.newmedialab.ldpath.api.backend.RDFBackend#dateTimeValue(java.lang.Object) */ public Date dateTimeValue(Node node) { String lexicalForm = stringValue(node); Date date = FormatUtils.parseDate(lexicalForm); if(date == null){ throw new IllegalArgumentException("could not parse xsd:dateTime from '"+ lexicalForm+"'!"); } else { return date; } }; @Override public abstract String stringValue(Node node); /** * Removes the first character from the supplied string if this is a plus * sign ('+'). Number strings with leading plus signs cannot be parsed by * methods such as {@link Integer#parseInt(String)}.

* Taken from the Sesame XMLDatatypeUtil. */ private static String trimPlusSign(String s) { return (s.length() > 0 && s.charAt(0) == '+') ? s.substring(1) : s; } /** * Utility to parse xsd:date strings * @param dateString * @return * @throws ParseException */ protected Date parseDate(String dateString) throws ParseException { synchronized (dateFormat) { return dateFormat.parse(dateString); } } /** * Utility to parse xsd:time strings * @param timeString * @return * @throws ParseException */ protected Date parseTime(String timeString) throws ParseException { synchronized (timeFormat) { return timeFormat.parse(timeString); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy