/*
* $Id$
*
* This file is part of the OpenLink Software Virtuoso Open-Source (VOS)
* project.
*
* Copyright (C) 1998-2012 OpenLink Software
*
* This project is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; only version 2 of the License, dated June 1991.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
package virtuoso.jena.driver;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import virtuoso.jdbc4.VirtuosoConnectionPoolDataSource;
import virtuoso.jdbc4.VirtuosoDataSource;
import virtuoso.sql.ExtendedString;
import virtuoso.sql.RdfBox;
import com.hp.hpl.jena.datatypes.RDFDatatype;
import com.hp.hpl.jena.datatypes.TypeMapper;
import com.hp.hpl.jena.graph.BulkUpdateHandler;
import com.hp.hpl.jena.graph.GraphEvents;
import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.graph.TransactionHandler;
import com.hp.hpl.jena.graph.Triple;
import com.hp.hpl.jena.graph.TripleMatch;
import com.hp.hpl.jena.graph.impl.GraphBase;
import com.hp.hpl.jena.rdf.model.AnonId;
import com.hp.hpl.jena.rdf.model.impl.ModelCom;
import com.hp.hpl.jena.shared.AddDeniedException;
import com.hp.hpl.jena.shared.DeleteDeniedException;
import com.hp.hpl.jena.shared.JenaException;
import com.hp.hpl.jena.shared.PrefixMapping;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
import com.hp.hpl.jena.util.iterator.NiceIterator;
public class VirtGraph extends GraphBase {
static {
VirtuosoQueryEngine.register();
}
static public final String DEFAULT = "virt:DEFAULT";
protected String graphName;
protected boolean readFromAllGraphs = false;
protected String url_hostlist;
protected String user;
protected String password;
protected boolean roundrobin = false;
protected int prefetchSize = 200;
protected Connection connection = null;
protected String ruleSet = null;
protected boolean useSameAs = false;
protected int queryTimeout = 0;
static final String sinsert = "sparql insert into graph iri(??) { `iri(??)` `iri(??)` `bif:__rdf_long_from_batch_params(??,??,??)` }";
static final String sdelete = "sparql delete from graph iri(??) {`iri(??)` `iri(??)` `bif:__rdf_long_from_batch_params(??,??,??)`}";
static final int BATCH_SIZE = 5000;
static final String utf8 = "charset=utf-8";
static final String charset = "UTF-8";
private VirtuosoConnectionPoolDataSource pds = new VirtuosoConnectionPoolDataSource();
private VirtuosoDataSource ds;
private boolean isDSconnection = false;
public VirtGraph() {
this(null, "jdbc:virtuoso://localhost:1111/charset=UTF-8", null, null,
false);
}
public VirtGraph(String graphName) {
this(graphName, "jdbc:virtuoso://localhost:1111/charset=UTF-8", null,
null, false);
}
public VirtGraph(String graphName, String _url_hostlist, String user,
String password) {
this(graphName, _url_hostlist, user, password, false);
}
public VirtGraph(String url_hostlist, String user, String password) {
this(null, url_hostlist, user, password, false);
}
public VirtGraph(String _graphName, VirtuosoDataSource _ds) {
super();
this.url_hostlist = _ds.getServerName();
this.graphName = _graphName;
this.user = _ds.getUser();
this.password = _ds.getPassword();
if (this.graphName == null)
this.graphName = DEFAULT;
try {
connection = _ds.getConnection();
isDSconnection = true;
ds = _ds;
ModelCom m = new ModelCom(this); // don't drop is it needed for
// initialize internal Jena
// classes
TypeMapper tm = TypeMapper.getInstance();
} catch (Exception e) {
throw new JenaException(e);
}
}
public VirtGraph(VirtuosoDataSource _ds) {
this(null, _ds);
}
public VirtGraph(String graphName, String _url_hostlist, String user,
String password, boolean _roundrobin) {
super();
this.url_hostlist = _url_hostlist.trim();
this.roundrobin = _roundrobin;
this.graphName = graphName;
this.user = user;
this.password = password;
if (this.graphName == null)
this.graphName = DEFAULT;
try {
if (url_hostlist.startsWith("jdbc:virtuoso://")) {
String url = url_hostlist;
if (url.toLowerCase().indexOf(utf8) == -1) {
if (url.charAt(url.length() - 1) != '/')
url = url + "/charset=UTF-8";
else
url = url + "charset=UTF-8";
}
if (roundrobin
&& url.toLowerCase().indexOf("roundrobin=") == -1) {
if (url.charAt(url.length() - 1) != '/')
url = url + "/roundrobin=1";
else
url = url + "roundrobin=1";
}
Class.forName("virtuoso.jdbc4.Driver");
connection = DriverManager.getConnection(url, user, password);
} else {
pds.setServerName(url_hostlist);
pds.setUser(user);
pds.setPassword(password);
pds.setCharset(charset);
pds.setRoundrobin(roundrobin);
javax.sql.PooledConnection pconn = pds.getPooledConnection();
connection = pconn.getConnection();
isDSconnection = true;
}
ModelCom m = new ModelCom(this); // don't drop is it needed for
// initialize internal Jena
// classes
TypeMapper tm = TypeMapper.getInstance();
} catch (Exception e) {
throw new JenaException(e);
}
}
// getters
public VirtuosoDataSource getDataSource() {
if (isDSconnection)
return (ds != null ? ds : (VirtuosoDataSource) pds);
else
return null;
}
public String getGraphName() {
return this.graphName;
}
public String getGraphUrl() {
return this.url_hostlist;
}
public String getGraphUser() {
return this.user;
}
public String getGraphPassword() {
return this.password;
}
public Connection getConnection() {
return this.connection;
}
public int getFetchSize() {
return this.prefetchSize;
}
public void setFetchSize(int sz) {
this.prefetchSize = sz;
}
public int getQueryTimeout() {
return this.queryTimeout;
}
public void setQueryTimeout(int seconds) {
this.queryTimeout = seconds;
}
public int getCount() {
return size();
}
public void remove(List triples) {
delete(triples.iterator(), null);
}
public void remove(Triple t) {
delete(t);
}
public boolean getReadFromAllGraphs() {
return readFromAllGraphs;
}
public void setReadFromAllGraphs(boolean val) {
readFromAllGraphs = val;
}
public String getRuleSet() {
return ruleSet;
}
public void setRuleSet(String _ruleSet) {
ruleSet = _ruleSet;
}
public boolean getSameAs() {
return useSameAs;
}
public void setSameAs(boolean _sameAs) {
useSameAs = _sameAs;
}
public void createRuleSet(String ruleSetName, String uriGraphRuleSet) {
checkOpen();
try {
java.sql.Statement st = createStatement();
st.execute("rdfs_rule_set('" + ruleSetName + "', '"
+ uriGraphRuleSet + "')");
st.close();
} catch (Exception e) {
throw new JenaException(e);
}
}
public void removeRuleSet(String ruleSetName, String uriGraphRuleSet) {
checkOpen();
try {
java.sql.Statement st = createStatement();
st.execute("rdfs_rule_set('" + ruleSetName + "', '"
+ uriGraphRuleSet + "', 1)");
st.close();
} catch (Exception e) {
throw new JenaException(e);
}
}
private static String escapeString(String s) {
StringBuffer buf = new StringBuffer(s.length());
int i = 0;
char ch;
while (i < s.length()) {
ch = s.charAt(i++);
if (ch == '\'')
buf.append('\\');
buf.append(ch);
}
return buf.toString();
}
protected java.sql.Statement createStatement() throws java.sql.SQLException {
checkOpen();
java.sql.Statement st = connection.createStatement();
if (queryTimeout > 0)
st.setQueryTimeout(queryTimeout);
st.setFetchSize(prefetchSize);
return st;
}
protected java.sql.PreparedStatement prepareStatement(String sql)
throws java.sql.SQLException {
checkOpen();
java.sql.PreparedStatement st = connection.prepareStatement(sql);
if (queryTimeout > 0)
st.setQueryTimeout(queryTimeout);
st.setFetchSize(prefetchSize);
return st;
}
// GraphBase overrides
public static String Node2Str(Node n) {
if (n.isURI()) {
return "<" + n + ">";
} else if (n.isBlank()) {
return "<_:" + n + ">";
} else if (n.isLiteral()) {
String s;
StringBuffer sb = new StringBuffer();
sb.append("'");
sb.append(escapeString(n.getLiteralValue().toString()));
sb.append("'");
s = n.getLiteralLanguage();
if (s != null && s.length() > 0) {
sb.append("@");
sb.append(s);
}
s = n.getLiteralDatatypeURI();
if (s != null && s.length() > 0) {
sb.append("^^<");
sb.append(s);
sb.append(">");
}
return sb.toString();
} else {
return "<" + n + ">";
}
}
void bindSubject(PreparedStatement ps, int col, Node n) throws SQLException {
if (n == null)
return;
if (n.isURI())
ps.setString(col, n.toString());
else if (n.isBlank())
ps.setString(col, "_:" + n.toString());
else
throw new SQLException(
"Only URI or Blank nodes can be used as subject");
}
void bindPredicate(PreparedStatement ps, int col, Node n)
throws SQLException {
if (n == null)
return;
if (n.isURI())
ps.setString(col, n.toString());
else
throw new SQLException("Only URI nodes can be used as predicate");
}
void bindObject(PreparedStatement ps, int col, Node n) throws SQLException {
if (n == null)
return;
if (n.isURI()) {
ps.setInt(col, 1);
ps.setString(col + 1, n.toString());
ps.setNull(col + 2, java.sql.Types.VARCHAR);
} else if (n.isBlank()) {
ps.setInt(col, 1);
ps.setString(col + 1, "_:" + n.toString());
ps.setNull(col + 2, java.sql.Types.VARCHAR);
} else if (n.isLiteral()) {
String llang = n.getLiteralLanguage();
String ltype = n.getLiteralDatatypeURI();
if (llang != null && llang.length() > 0) {
ps.setInt(col, 5);
ps.setString(col + 1, n.getLiteralValue().toString());
ps.setString(col + 2, n.getLiteralLanguage());
} else if (ltype != null && ltype.length() > 0) {
ps.setInt(col, 4);
ps.setString(col + 1, n.getLiteralValue().toString());
ps.setString(col + 2, n.getLiteralDatatypeURI());
} else {
ps.setInt(col, 3);
ps.setString(col + 1, n.getLiteralValue().toString());
ps.setNull(col + 2, java.sql.Types.VARCHAR);
}
} else {
ps.setInt(col, 3);
ps.setString(col + 1, n.toString());
ps.setNull(col + 2, java.sql.Types.VARCHAR);
}
}
// --java5 or newer @Override
public void performAdd(Triple t) {
java.sql.PreparedStatement ps;
try {
ps = prepareStatement(sinsert);
ps.setString(1, this.graphName);
bindSubject(ps, 2, t.getSubject());
bindPredicate(ps, 3, t.getPredicate());
bindObject(ps, 4, t.getObject());
ps.execute();
ps.close();
} catch (Exception e) {
throw new AddDeniedException(e.toString());
}
}
public void performDelete(Triple t) {
java.sql.PreparedStatement ps;
try {
ps = prepareStatement(sdelete);
ps.setString(1, this.graphName);
bindSubject(ps, 2, t.getSubject());
bindPredicate(ps, 3, t.getPredicate());
bindObject(ps, 4, t.getObject());
ps.execute();
ps.close();
} catch (Exception e) {
throw new DeleteDeniedException(e.toString());
}
}
/**
* more efficient
*/
// --java5 or newer @Override
protected int graphBaseSize() {
StringBuffer sb = new StringBuffer(
"select count(*) from (sparql define input:storage \"\" ");
if (ruleSet != null)
sb.append(" define input:inference '" + ruleSet + "'\n ");
if (useSameAs)
sb.append(" define input:same-as \"yes\"\n ");
if (readFromAllGraphs)
sb.append(" select * where {?s ?p ?o })f");
else
sb.append(" select * where { graph `iri(??)` { ?s ?p ?o }})f");
ResultSet rs = null;
int ret = 0;
checkOpen();
try {
java.sql.PreparedStatement ps = prepareStatement(sb.toString());
if (!readFromAllGraphs)
ps.setString(1, graphName);
rs = ps.executeQuery();
if (rs.next())
ret = rs.getInt(1);
rs.close();
ps.close();
} catch (Exception e) {
throw new JenaException(e);
}
return ret;
}
/**
* maybe more efficient than default impl
*
*/
// --java5 or newer @Override
protected boolean graphBaseContains(Triple t) {
ResultSet rs = null;
String S, P, O;
StringBuffer sb = new StringBuffer("sparql define input:storage \"\" ");
String exec_text;
checkOpen();
S = " ?s ";
P = " ?p ";
O = " ?o ";
if (!Node.ANY.equals(t.getSubject()))
S = Node2Str(t.getSubject());
if (!Node.ANY.equals(t.getPredicate()))
P = Node2Str(t.getPredicate());
if (!Node.ANY.equals(t.getObject()))
O = Node2Str(t.getObject());
if (ruleSet != null)
sb.append(" define input:inference '" + ruleSet + "'\n ");
if (useSameAs)
sb.append(" define input:same-as \"yes\"\n ");
if (readFromAllGraphs)
sb.append(" select * where { " + S + " " + P + " " + O
+ " } limit 1");
else
sb.append(" select * where { graph <" + graphName + "> { " + S
+ " " + P + " " + O + " }} limit 1");
try {
java.sql.Statement stmt = createStatement();
rs = stmt.executeQuery(sb.toString());
boolean ret = rs.next();
rs.close();
stmt.close();
return ret;
} catch (Exception e) {
throw new JenaException(e);
}
}
// --java5 or newer @Override
public ExtendedIterator<Triple> graphBaseFind(TripleMatch tm) {
String S, P, O;
StringBuffer sb = new StringBuffer("sparql ");
checkOpen();
S = " ?s ";
P = " ?p ";
O = " ?o ";
if (tm.getMatchSubject() != null)
S = Node2Str(tm.getMatchSubject());
if (tm.getMatchPredicate() != null)
P = Node2Str(tm.getMatchPredicate());
if (tm.getMatchObject() != null)
O = Node2Str(tm.getMatchObject());
if (ruleSet != null)
sb.append(" define input:inference '" + ruleSet + "'\n ");
if (useSameAs)
sb.append(" define input:same-as \"yes\"\n ");
if (readFromAllGraphs)
sb.append(" select * where { " + S + " " + P + " " + O + " }");
else
sb.append(" select * from <" + graphName + "> where { " + S + " "
+ P + " " + O + " }");
try {
java.sql.PreparedStatement stmt;
stmt = prepareStatement(sb.toString());
return new VirtResSetIter(this, stmt.executeQuery(), tm, stmt);
} catch (Exception e) {
throw new JenaException(e);
}
}
// --java5 or newer @Override
public void close() {
try {
super.close(); // will set closed = true
connection.close();
} catch (Exception e) {
throw new JenaException(e);
}
}
// Extra functions
public void clear() {
clearGraph(this.graphName);
getEventManager().notifyEvent(this, GraphEvents.removeAll);
}
public void read(String url, String type) {
String exec_text;
exec_text = "sparql load \"" + url + "\" into graph <" + graphName
+ ">";
checkOpen();
try {
java.sql.Statement stmt = createStatement();
stmt.execute(exec_text);
stmt.close();
} catch (Exception e) {
throw new JenaException(e);
}
}
// --java5 or newer @SuppressWarnings("unchecked")
void add(Iterator<Triple> it, List<Triple> list) {
try {
PreparedStatement ps = prepareStatement(sinsert);
int count = 0;
while (it.hasNext()) {
Triple t = (Triple) it.next();
if (list != null)
list.add(t);
ps.setString(1, this.graphName);
bindSubject(ps, 2, t.getSubject());
bindPredicate(ps, 3, t.getPredicate());
bindObject(ps, 4, t.getObject());
ps.addBatch();
count++;
if (count > BATCH_SIZE) {
ps.executeBatch();
ps.clearBatch();
count = 0;
}
}
if (count > 0) {
ps.executeBatch();
ps.clearBatch();
}
ps.close();
} catch (Exception e) {
throw new JenaException(e);
}
}
void delete(Iterator<Triple> it, List<Triple> list) {
try {
while (it.hasNext()) {
Triple triple = (Triple) it.next();
if (list != null)
list.add(triple);
performDelete(triple);
}
} catch (Exception e) {
throw new JenaException(e);
}
}
void delete_match(TripleMatch tm) {
String S, P, O;
Node nS, nP, nO;
checkOpen();
S = "?s";
P = "?p";
O = "?o";
nS = tm.getMatchSubject();
nP = tm.getMatchPredicate();
nO = tm.getMatchObject();
try {
if (nS == null && nP == null && nO == null) {
clearGraph(this.graphName);
} else if (nS != null && nP != null && nO != null) {
java.sql.PreparedStatement ps;
ps = prepareStatement(sdelete);
ps.setString(1, this.graphName);
bindSubject(ps, 2, nS);
bindPredicate(ps, 3, nP);
bindObject(ps, 4, nO);
ps.execute();
ps.close();
} else {
if (nS != null)
S = Node2Str(nS);
if (nP != null)
P = Node2Str(nP);
if (nO != null)
O = Node2Str(nO);
String query = "sparql delete from graph <" + this.graphName
+ "> { " + S + " " + P + " " + O + " } from <"
+ this.graphName + "> where { " + S + " " + P + " " + O
+ " }";
java.sql.Statement stmt = createStatement();
stmt.execute(query);
stmt.close();
}
} catch (Exception e) {
throw new DeleteDeniedException(e.toString());
}
}
void clearGraph(String name) {
String query = "sparql clear graph iri(??)";
checkOpen();
try {
java.sql.PreparedStatement ps = prepareStatement(query);
ps.setString(1, name);
ps.execute();
ps.close();
} catch (Exception e) {
throw new JenaException(e);
}
}
public ExtendedIterator reifierTriples(TripleMatch m) {
return NiceIterator.emptyIterator();
}
public int reifierSize() {
return 0;
}
// --java5 or newer @Override
public TransactionHandler getTransactionHandler() {
return new VirtTransactionHandler(this);
}
// --java5 or newer @Override
public BulkUpdateHandler getBulkUpdateHandler() {
if (bulkHandler == null)
bulkHandler = new VirtBulkUpdateHandler(this);
return bulkHandler;
}
protected VirtPrefixMapping m_prefixMapping = null;
public PrefixMapping getPrefixMapping() {
if (m_prefixMapping == null)
m_prefixMapping = new VirtPrefixMapping(this);
return m_prefixMapping;
}
public static Node Object2Node(Object o) {
if (o == null)
return null;
if (o instanceof ExtendedString) {
ExtendedString vs = (ExtendedString) o;
if (vs.getIriType() == ExtendedString.IRI
&& (vs.getStrType() & 0x01) == 0x01) {
if (vs.toString().indexOf("_:") == 0)
return Node.createAnon(AnonId.create(vs.toString()
.substring(2))); // _:
else
return Node.createURI(vs.toString());
} else if (vs.getIriType() == ExtendedString.BNODE) {
return Node.createAnon(AnonId
.create(vs.toString().substring(9))); // nodeID://
} else {
return Node.createLiteral(vs.toString());
}
} else if (o instanceof RdfBox) {
RdfBox rb = (RdfBox) o;
String rb_type = rb.getType();
RDFDatatype dt = null;
if (rb_type != null)
dt = TypeMapper.getInstance().getSafeTypeByName(rb_type);
return Node.createLiteral(rb.toString(), rb.getLang(), dt);
} else if (o instanceof java.lang.Integer) {
RDFDatatype dt = null;
dt = TypeMapper.getInstance().getSafeTypeByName(
"http://www.w3.org/2001/XMLSchema#integer");
return Node.createLiteral(o.toString(), null, dt);
} else if (o instanceof java.lang.Short) {
RDFDatatype dt = null;
// dt =
// TypeMapper.getInstance().getSafeTypeByName("http://www.w3.org/2001/XMLSchema#short");
dt = TypeMapper.getInstance().getSafeTypeByName(
"http://www.w3.org/2001/XMLSchema#integer");
return Node.createLiteral(o.toString(), null, dt);
} else if (o instanceof java.lang.Float) {
RDFDatatype dt = null;
dt = TypeMapper.getInstance().getSafeTypeByName(
"http://www.w3.org/2001/XMLSchema#float");
return Node.createLiteral(o.toString(), null, dt);
} else if (o instanceof java.lang.Double) {
RDFDatatype dt = null;
dt = TypeMapper.getInstance().getSafeTypeByName(
"http://www.w3.org/2001/XMLSchema#double");
return Node.createLiteral(o.toString(), null, dt);
} else if (o instanceof java.math.BigDecimal) {
RDFDatatype dt = null;
dt = TypeMapper.getInstance().getSafeTypeByName(
"http://www.w3.org/2001/XMLSchema#decimal");
return Node.createLiteral(o.toString(), null, dt);
} else if (o instanceof java.sql.Blob) {
RDFDatatype dt = null;
dt = TypeMapper.getInstance().getSafeTypeByName(
"http://www.w3.org/2001/XMLSchema#hexBinary");
return Node.createLiteral(o.toString(), null, dt);
} else if (o instanceof java.sql.Date) {
RDFDatatype dt = null;
dt = TypeMapper.getInstance().getSafeTypeByName(
"http://www.w3.org/2001/XMLSchema#date");
return Node.createLiteral(o.toString(), null, dt);
} else if (o instanceof java.sql.Timestamp) {
RDFDatatype dt = null;
dt = TypeMapper.getInstance().getSafeTypeByName(
"http://www.w3.org/2001/XMLSchema#dateTime");
return Node.createLiteral(Timestamp2String((java.sql.Timestamp) o),
null, dt);
} else if (o instanceof java.sql.Time) {
RDFDatatype dt = null;
dt = TypeMapper.getInstance().getSafeTypeByName(
"http://www.w3.org/2001/XMLSchema#time");
return Node.createLiteral(o.toString(), null, dt);
} else {
return Node.createLiteral(o.toString());
}
}
private static String Timestamp2String(java.sql.Timestamp v) {
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(v);
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1;
int day = cal.get(Calendar.DAY_OF_MONTH);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
int second = cal.get(Calendar.SECOND);
int nanos = v.getNanos();
String yearS;
String monthS;
String dayS;
String hourS;
String minuteS;
String secondS;
String nanosS;
String zeros = "000000000";
String yearZeros = "0000";
StringBuffer timestampBuf;
if (year < 1000) {
yearS = "" + year;
yearS = yearZeros.substring(0, (4 - yearS.length())) + yearS;
} else {
yearS = "" + year;
}
if (month < 10)
monthS = "0" + month;
else
monthS = Integer.toString(month);
if (day < 10)
dayS = "0" + day;
else
dayS = Integer.toString(day);
if (hour < 10)
hourS = "0" + hour;
else
hourS = Integer.toString(hour);
if (minute < 10)
minuteS = "0" + minute;
else
minuteS = Integer.toString(minute);
if (second < 10)
secondS = "0" + second;
else
secondS = Integer.toString(second);
if (nanos == 0) {
nanosS = "0";
} else {
nanosS = Integer.toString(nanos);
// Add leading 0
nanosS = zeros.substring(0, (9 - nanosS.length())) + nanosS;
// Truncate trailing 0
char[] nanosChar = new char[nanosS.length()];
nanosS.getChars(0, nanosS.length(), nanosChar, 0);
int truncIndex = 8;
while (nanosChar[truncIndex] == '0') {
truncIndex--;
}
nanosS = new String(nanosChar, 0, truncIndex + 1);
}
timestampBuf = new StringBuffer();
timestampBuf.append(yearS);
timestampBuf.append("-");
timestampBuf.append(monthS);
timestampBuf.append("-");
timestampBuf.append(dayS);
timestampBuf.append("T");
timestampBuf.append(hourS);
timestampBuf.append(":");
timestampBuf.append(minuteS);
timestampBuf.append(":");
timestampBuf.append(secondS);
timestampBuf.append(".");
timestampBuf.append(nanosS);
return (timestampBuf.toString());
}
}