/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/citations/trunk/citations-impl/impl/src/java/org/sakaiproject/citation/impl/DbCitationService.java $
* $Id: DbCitationService.java 119774 2013-02-08 09:58:57Z a.fish@lancaster.ac.uk $
***********************************************************************************
*
* Copyright (c) 2006, 2007, 2008 The Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package org.sakaiproject.citation.impl;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.citation.api.Citation;
import org.sakaiproject.citation.api.CitationCollection;
import org.sakaiproject.citation.api.CitationService;
import org.sakaiproject.citation.api.Schema;
import org.sakaiproject.citation.api.Schema.Field;
import org.sakaiproject.db.api.SqlReader;
import org.sakaiproject.db.api.SqlService;
import org.sakaiproject.id.cover.IdManager;
import org.sakaiproject.thread_local.cover.ThreadLocalManager;
import org.sakaiproject.time.api.Time;
import org.sakaiproject.time.cover.TimeService;
/**
*
*/
public class DbCitationService extends BaseCitationService
{
/**
*
*/
public class DbCitationStorage implements Storage
{
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#addCitation(java.lang.String)
*/
public Citation addCitation(String mediatype)
{
Citation citation = this.createCitation(mediatype);
return citation;
}
public CitationCollection addCollection(Map attributes, List citations)
{
CitationCollection collection = this.createCollection(attributes, citations);
return collection;
}
public Schema addSchema(Schema schema)
{
schema = this.createSchema(schema);
return schema;
}
public boolean checkCitation(String citationId)
{
boolean check = this.validCitation(citationId);
return check;
}
public boolean checkCollection(String collectionId)
{
boolean check = this.validCollection(collectionId);
return check;
}
public boolean checkSchema(String schemaId)
{
boolean check = this.validSchema(schemaId);
return check;
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#close()
*/
public void close()
{
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#copyAll(java.lang.String)
*/
public CitationCollection copyAll(String collectionId)
{
CitationCollection copy = this.duplicateAll(collectionId);
return copy;
}
public Citation getCitation(String citationId)
{
Citation citation = this.retrieveCitation(citationId);
return citation;
}
public CitationCollection getCollection(String collectionId)
{
CitationCollection collection = this.retrieveCollection(collectionId);
return collection;
}
public Schema getSchema(String schemaId)
{
BasicSchema schema = (BasicSchema) ThreadLocalManager.get(schemaId);
if(schema == null)
{
schema = (BasicSchema) this.retrieveSchema(schemaId);
}
else
{
schema = new BasicSchema(schema);
}
return schema;
}
public List getSchemas()
{
List schemas = (List) ThreadLocalManager.get("DbCitationStorage.getSchemas");
if(schemas == null)
{
schemas = this.retrieveSchemas();
}
else
{
List rv = new Vector();
Iterator it = schemas.iterator();
while(it.hasNext())
{
Schema schema = (Schema) it.next();
rv.add(new BasicSchema(schema));
}
schemas = rv;
}
return schemas;
}
public List listSchemas()
{
List schemaIds = (List) ThreadLocalManager.get("DbCitationStorage.listSchemas");
if(schemaIds == null)
{
schemaIds = this.retrieveSchemaList();
}
else
{
schemaIds = new Vector(schemaIds);
}
return schemaIds;
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#open()
*/
public void open()
{
}
public void putSchemas(Collection schemas)
{
this.insertSchemas(schemas);
}
public void removeCitation(Citation edit)
{
this.deleteCitation(edit);
}
public void removeCollection(CitationCollection edit)
{
this.deleteCollection(edit);
}
public void removeSchema(Schema schema)
{
this.deleteSchema(schema);
}
public void saveCitation(Citation edit)
{
this.commitCitation(edit);
}
public void saveCollection(CitationCollection collection)
{
this.commitCollection(collection);
}
public void updateSchema(Schema schema)
{
this.reviseSchema(schema);
}
public void updateSchemas(Collection schemas)
{
this.reviseSchemas(schemas);
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#saveCitation(org.sakaiproject.citation.api.Citation)
*/
protected void commitCitation(Citation citation)
{
deleteCitation(citation);
String statement = "insert into " + m_citationTableName + " (" + m_citationTableId + ", PROPERTY_NAME, PROPERTY_VALUE) values ( ?, ?, ? )";
String citationId = citation.getId();
boolean ok = true;
Object[] fields = new Object[3];
fields[0] = citationId;
if(citation.getSchema() != null)
{
fields[1] = PROP_MEDIATYPE;
fields[2] = citation.getSchema().getIdentifier();
ok = m_sqlService.dbWrite(statement, fields);
}
String displayName = citation.getDisplayName();
if(displayName != null)
{
fields[1] = PROP_DISPLAYNAME;
fields[2] = displayName.trim();
ok = m_sqlService.dbWrite(statement, fields);
}
if(citation.isAdded())
{
fields[1] = PROP_ADDED;
fields[2] = Boolean.TRUE.toString();
ok = m_sqlService.dbWrite(statement, fields);
}
List names = citation.listCitationProperties();
Iterator nameIt = names.iterator();
while(nameIt.hasNext())
{
String name = (String) nameIt.next();
Object value = citation.getCitationProperty(name, false);
if(value instanceof List)
{
List list = (List) value;
for(int i = 0; i < list.size(); i++)
{
Object item = list.get(i);
fields[1] = name + PROPERTY_NAME_DELIMITOR + i;
fields[2] = item;
ok = m_sqlService.dbWrite(statement, fields);
}
}
else if(value instanceof String)
{
fields[1] = name;
fields[2] = value;
ok = m_sqlService.dbWrite(statement, fields);
}
else
{
M_log.debug("DbCitationStorage.saveCitation value not List or String: " + value.getClass().getCanonicalName() + " " + value);
fields[1] = name;
fields[2] = value;
ok = m_sqlService.dbWrite(statement, fields);
}
}
int urlCount = 0;
Map<String,UrlWrapper> urls = ((BasicCitation) citation).m_urls;
if(((BasicCitation) citation).m_urls != null)
{
for(Map.Entry<String, UrlWrapper> entry : ((Map<String,UrlWrapper>) ((BasicCitation) citation).m_urls).entrySet()) {
UrlWrapper wrapper = (UrlWrapper) entry.getValue();
fields[1] = PROP_HAS_URL + PROPERTY_NAME_DELIMITOR + urlCount;
fields[2] = entry.getKey();
ok = m_sqlService.dbWrite(statement, fields);
commitUrl(entry.getKey(), wrapper.getLabel(), wrapper.getUrl(), wrapper.addPrefix());
urlCount++;
}
}
// preferred url
if(citation.hasPreferredUrl())
{
fields[1] = PROP_HAS_PREFERRED_URL;
fields[2] = citation.getPreferredUrlId();
ok = m_sqlService.dbWrite(statement, fields);
}
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#saveCollection(java.util.Collection)
*/
protected void commitCollection(CitationCollection collection)
{
deleteCollection(collection);
String statement = "insert into " + m_collectionTableName + " (" + m_collectionTableId + ",PROPERTY_NAME,PROPERTY_VALUE) values ( ?, ?, ? )";
String orderStatement = "insert into " + m_collectionOrderTableName + " VALUES(?,?,?)";
boolean ok = true;
String collectionId = collection.getId();
Object[] fields = new Object[3];
fields[0] = collectionId;
Object[] orderFields = new Object[3];
orderFields[0] = collectionId;
List members = collection.getCitations();
Iterator citationIt = members.iterator();
while(citationIt.hasNext())
{
Citation citation = (Citation) citationIt.next();
save(citation);
// Insert the ordering table data.
orderFields[1] = citation.getId();
orderFields[2] = citation.getPosition();
ok = m_sqlService.dbWrite(orderStatement, orderFields);
}
long mostRecentUpdate = TimeService.newTime().getTime();
fields[1] = PROP_MOST_RECENT_UPDATE;
fields[2] = Long.toString(mostRecentUpdate);
ok = m_sqlService.dbWrite(statement, fields);
fields[1] = PROP_SORT_ORDER;
fields[2] = collection.getSort();
ok = m_sqlService.dbWrite(statement, fields);
}
/**
* @param id
* @param label
* @param url
*/
protected void commitUrl(String id, String label, String url, boolean addPrefix)
{
deleteUrl(id);
String statement = "insert into " + m_citationTableName + " (" + m_citationTableId + ", PROPERTY_NAME, PROPERTY_VALUE) values ( ?, ?, ? )";
boolean ok = true;
Object[] fields = new Object[3];
fields[0] = id;
fields[1] = PROP_URL_LABEL;
fields[2] = label;
ok = m_sqlService.dbWrite(statement, fields);
fields[1] = PROP_URL_STRING;
fields[2] = url;
ok = m_sqlService.dbWrite(statement, fields);
fields[1] = PROP_URL_ADD_PREFIX;
fields[2] = addPrefix ? Citation.ADD_PREFIX_TEXT
: Citation.OMIT_PREFIX_TEXT;
ok = m_sqlService.dbWrite(statement, fields);
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#addCitation(java.lang.String)
*/
protected Citation createCitation(String mediatype)
{
// need to create a citation (referred to below as "edit")
Citation edit = new BasicCitation(mediatype);
String statement = "insert into " + m_citationTableName + " (" + m_citationTableId + ", PROPERTY_NAME, PROPERTY_VALUE) values ( ?, ?, ? )";
String citationId = edit.getId();
Object[] fields = new Object[3];
fields[0] = citationId;
fields[1] = PROP_MEDIATYPE;
fields[2] = edit.getSchema().getIdentifier();
boolean ok = m_sqlService.dbWrite(statement, fields);
List names = edit.listCitationProperties();
boolean first = true;
Iterator nameIt = names.iterator();
while(nameIt.hasNext())
{
String name = (String) nameIt.next();
Object value = edit.getCitationProperty(name, false);
fields[1] = name;
fields[2] = value;
// process the insert
ok = m_sqlService.dbWrite(statement, fields);
}
return edit;
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#putCollection(java.lang.String, java.util.Map, java.util.List)
*/
protected CitationCollection createCollection(Map attributes, List citations)
{
// need to create a collection (referred to below as "edit")
BasicCitationCollection edit = new BasicCitationCollection(attributes, citations);
String statement = "insert into " + m_collectionTableName + " (" + m_collectionTableId + ",PROPERTY_NAME,PROPERTY_VALUE) values ( ?, ?, ? )";
Object[] fields = new Object[3];
fields[0] = edit.getId();
boolean ok = true;
List members = edit.getCitations();
Iterator citationIt = members.iterator();
while(citationIt.hasNext())
{
Citation citation = (Citation) citationIt.next();
if(citation instanceof BasicCitation && ((BasicCitation) citation).isTemporary())
{
((BasicCitation) citation).m_id = IdManager.createUuid();
((BasicCitation) citation).m_temporary = false;
((BasicCitation) citation).m_serialNumber = null;
}
commitCitation(citation);
}
edit.m_mostRecentUpdate = TimeService.newTime().getTime();
fields[1] = PROP_MOST_RECENT_UPDATE;
fields[2] = Long.toString(edit.m_mostRecentUpdate);
ok = m_sqlService.dbWrite(statement, fields);
return edit;
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#putSchema(org.sakaiproject.citation.api.Schema)
*/
protected Schema createSchema(Schema schema)
{
String statement = "insert into " + m_schemaTableName + " (" + m_schemaTableId + ",PROPERTY_NAME,PROPERTY_VALUE) values ( ?, ?, ? )";
String schemaId = schema.getIdentifier();
boolean ok = true;
Object[] fields = new Object[3];
fields[0] = schemaId;
fields[1] = PROPERTY_HAS_FIELD;
List schemaFields = schema.getFields();
for(int i = 0; i < schemaFields.size(); i++)
{
Field field = (Field) schemaFields.get(i);
if(field instanceof BasicField)
{
((BasicField) field).setOrder(i);
}
insertSchemaField(field, schemaId);
fields[2] = field.getIdentifier();
ok = m_sqlService.dbWrite(statement, fields);
}
Iterator namespaceIt = schema.getNamespaceAbbreviations().iterator();
while(namespaceIt.hasNext())
{
String abbrev = (String) namespaceIt.next();
String namespaceUri = schema.getNamespaceUri(abbrev);
if(abbrev != null && namespaceUri != null)
{
fields[0] = schemaId;
fields[1] = PROPERTY_HAS_NAMESPACE;
fields[2] = namespaceUri;
ok = m_sqlService.dbWrite(statement, fields);
fields[0] = namespaceUri;
fields[1] = PROPERTY_HAS_ABBREVIATION;
fields[2] = abbrev;
ok = m_sqlService.dbWrite(statement, fields);
}
}
if(schema.getNamespaceAbbrev() != null && ! "".equals(schema.getNamespaceAbbrev().trim()))
{
fields[0] = schemaId;
fields[1] = PROPERTY_NAMESPACE;
fields[2] = schema.getNamespaceAbbrev();
ok = m_sqlService.dbWrite(statement, fields);
}
return schema;
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#removeCitation(org.sakaiproject.citation.api.Citation)
*/
protected void deleteCitation(Citation edit)
{
String statement = "delete from " + m_citationTableName + " where (" + m_citationTableId + " = ?)";
Object fields[] = new Object[1];
fields[0] = edit.getId();
boolean ok = m_sqlService.dbWrite(statement, fields);
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#removeCollection(org.sakaiproject.citation.api.CitationCollection)
*/
protected void deleteCollection(CitationCollection edit)
{
String statement = "delete from " + m_collectionTableName + " where (" + m_collectionTableId + " = ?)";
Object fields[] = new Object[1];
fields[0] = edit.getId();
boolean ok = m_sqlService.dbWrite(statement, fields);
statement = "delete from " + m_collectionOrderTableName + " where (" + m_collectionTableId + " = ?)";
ok = m_sqlService.dbWrite(statement, new Object[] {edit.getId()});
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#removeSchema(org.sakaiproject.citation.api.Schema)
*/
protected void deleteSchema(Schema schema)
{
String statement = "delete from " + m_schemaTableName + " where (" + m_schemaTableId + " = ?)";
Object fields[] = new Object[1];
fields[0] = schema.getIdentifier();
boolean ok = m_sqlService.dbWrite(statement, fields);
// need to remove schema fields also
if(ok)
{
String statement2 = "delete from " + m_schemaFieldTableName + " where (" + m_schemaTableId + " = ?)";
ok = m_sqlService.dbWrite(statement2, fields);
}
}
/**
* @param id
*/
protected void deleteUrl(String id)
{
String statement = "delete from " + m_citationTableName + " where (" + m_citationTableId + " = ?)";
Object fields[] = new Object[1];
fields[0] = id;
boolean ok = m_sqlService.dbWrite(statement, fields);
}
protected CitationCollection duplicateAll(String collectionId)
{
CitationCollection original = this.retrieveCollection(collectionId);
CitationCollection copy = null;
if(original != null)
{
copy = new BasicCitationCollection();
Iterator it = original.iterator();
while(it.hasNext())
{
Citation citation = (Citation) it.next();
BasicCitation newCite = new BasicCitation(citation.getSchema().getIdentifier());
newCite.copy(citation);
copy.add(newCite);
}
this.commitCollection(copy);
}
return copy;
}
/**
* @param citationId
* @return
*/
protected boolean getAdded(String citationId)
{
String statement = "select PROPERTY_VALUE from " + m_citationTableName + " where (CITATION_ID = ? and PROPERTY_NAME = ?)";
Object fields[] = new Object[2];
fields[0] = citationId;
fields[1] = PROP_ADDED;
List list = m_sqlService.dbRead(statement, fields, null);
return ! list.isEmpty();
}
protected String getMediatype(String citationId)
{
String statement = "select PROPERTY_VALUE from " + m_citationTableName + " where (CITATION_ID = ? and PROPERTY_NAME = ?)";
Object fields[] = new Object[2];
fields[0] = citationId;
fields[1] = PROP_MEDIATYPE;
List list = m_sqlService.dbRead(statement, fields, null);
String rv = UNKNOWN_TYPE;
if(! list.isEmpty())
{
rv = (String) list.get(0);
}
return rv;
}
protected void insertSchemaField(Field field, String schemaId)
{
String statement = "insert into " + m_schemaFieldTableName + " (" + m_schemaTableId + "," + m_schemaFieldTableId + ",PROPERTY_NAME,PROPERTY_VALUE) values ( ?, ?, ?, ? )";
boolean ok = true;
Object[] fields = new Object[4];
fields[0] = schemaId;
fields[1] = field.getIdentifier();
if(field instanceof BasicField)
{
int order = ((BasicField) field).getOrder();
fields[2] = PROPERTY_HAS_ORDER;
fields[3] = new Integer(order).toString();
// process the insert
ok = m_sqlService.dbWrite(statement, fields);
}
// PROPERTY_NAMESPACE namespace;
if(field.getNamespaceAbbreviation() != null && ! "".equals(field.getNamespaceAbbreviation().trim()))
{
fields[2] = PROPERTY_NAMESPACE;
fields[3] = field.getNamespaceAbbreviation();
// process the insert
ok = m_sqlService.dbWrite(statement, fields);
}
// PROPERTY_LABEL label;
if(field.getLabel() != null && ! "".equals(field.getLabel().trim()))
{
fields[2] = PROPERTY_LABEL;
fields[3] = field.getLabel();
// process the insert
ok = m_sqlService.dbWrite(statement, fields);
}
// PROPERTY_DESCRIPTION description;
if(field.getDescription() != null && ! "".equals(field.getDescription().trim()))
{
fields[2] = PROPERTY_DESCRIPTION;
fields[3] = field.getDescription();
// process the insert
ok = m_sqlService.dbWrite(statement, fields);
}
// PROPERTY_REQUIRED required;
fields[2] = PROPERTY_REQUIRED;
fields[3] = new Boolean(field.isRequired()).toString();
ok = m_sqlService.dbWrite(statement, fields);
// PROPERTY_MINCARDINALITY minCardinality;
fields[2] = PROPERTY_MINCARDINALITY;
fields[3] = new Integer(field.getMinCardinality()).toString();
ok = m_sqlService.dbWrite(statement, fields);
// PROPERTY_MAXCARDINALITY maxCardinality;
fields[2] = PROPERTY_MAXCARDINALITY;
fields[3] = new Integer(field.getMaxCardinality()).toString();
ok = m_sqlService.dbWrite(statement, fields);
// PROPERTY_DEFAULTVALUE defaultValue;
if(field.getDefaultValue() != null)
{
fields[2] = PROPERTY_DEFAULTVALUE;
fields[3] = field.getDefaultValue().toString();
// process the insert
ok = m_sqlService.dbWrite(statement, fields);
}
// PROPERTY_VALUETYPE valueType;
if(field.getValueType() != null && ! "".equals(field.getValueType().trim()))
{
fields[2] = PROPERTY_VALUETYPE;
fields[3] = field.getValueType();
// process the insert
ok = m_sqlService.dbWrite(statement, fields);
}
String risIdentifier = field.getIdentifier(RIS_FORMAT);
if(risIdentifier != null && ! risIdentifier.trim().equals(""))
{
fields[2] = PROP_HAS_RIS_IDENTIFIER;
fields[3] = risIdentifier;
// process the insert
ok = m_sqlService.dbWrite(statement, fields);
}
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#putSchemas(java.util.Collection)
*/
protected void insertSchemas(Collection schemas)
{
Iterator it = schemas.iterator();
while(it.hasNext())
{
Schema schema = (Schema) it.next();
createSchema(schema);
// ThreadLocalManager.set(schema.getIdentifier(), schema);
}
//ThreadLocalManager.set("DbCitationStorage.listSchemas", null);
//ThreadLocalManager.set("DbCitationStorage.getSchemas", null);
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#getCitation(java.lang.String)
*/
protected Citation retrieveCitation(String citationId)
{
String schemaId = getMediatype(citationId);
boolean added = getAdded(citationId);
Schema schema = retrieveSchema(schemaId);
BasicCitation edit = new BasicCitation(citationId, schema);
edit.setAdded(added);
String statement = "select CITATION_ID, PROPERTY_NAME, PROPERTY_VALUE from " + m_citationTableName + " where (CITATION_ID = ?) order by PROPERTY_NAME";
Object fields[] = new Object[1];
fields[0] = citationId;
List triples = m_sqlService.dbRead(statement, fields, new TripleReader());
Iterator it = triples.iterator();
while(it.hasNext())
{
Triple triple = (Triple) it.next();
if(triple.isValid())
{
String name = triple.getName();
String order = "0";
Matcher matcher = MULTIVALUED_PATTERN.matcher(name);
if(matcher.matches())
{
name = matcher.group(1);
order = matcher.group(2);
}
if(PROP_HAS_URL.equals(name))
{
String id = (String) triple.getValue();
fields[0] = id;
List urlfields = m_sqlService.dbRead(statement, fields, new TripleReader());
String label = null;
String url = null;
boolean addPrefix = false;
Iterator urlFieldIt = urlfields.iterator();
while(urlFieldIt.hasNext())
{
Triple urlField = (Triple) urlFieldIt.next();
if(PROP_URL_LABEL.equals(urlField.getName()))
{
label = (String) urlField.getValue();
}
else if(PROP_URL_STRING.equals(urlField.getName()))
{
url = (String) urlField.getValue();
}
else if(PROP_URL_ADD_PREFIX.equals(urlField.getName()))
{
String enabled = (String) urlField.getValue();
addPrefix = Citation.ADD_PREFIX_TEXT.equals(enabled);
}
}
edit.m_urls.put(id, new UrlWrapper(label, url, addPrefix));
}
else if(PROP_HAS_PREFERRED_URL.equals(name))
{
edit.m_preferredUrl = (String) triple.getValue();
}
else if(PROP_DISPLAYNAME.equals(name.trim()))
{
edit.setDisplayName(triple.getValue().toString());
}
else if (PROP_MEDIATYPE.equals(name))
{
// Ignore, handled before we started processing properties..
}
else if (PROP_ADDED.equals(name))
{
// Ignore, handled before we started processing properties.
}
else
{
// Don't need to worry about multivalued propertie
edit.setCitationProperty(name, triple.getValue());
}
}
}
return edit;
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#getCollection(java.lang.String)
*/
protected CitationCollection retrieveCollection(String collectionId)
{
String statement = "select COLLECTION_ID, PROPERTY_NAME, PROPERTY_VALUE from " + m_collectionTableName + " where (COLLECTION_ID = ?)";
BasicCitationCollection edit = new BasicCitationCollection(collectionId);
Object fields[] = new Object[1];
fields[0] = collectionId;
List triples = m_sqlService.dbRead(statement, fields, new TripleReader());
int position = 1;
Iterator it = triples.iterator();
while(it.hasNext())
{
Triple triple = (Triple) it.next();
if(triple.isValid())
{
if(triple.getName().startsWith(PROPERTY_HAS_CITATION))
{
// SAK-22296. Cunningly move the citation links into the new ordering table
m_sqlService.dbWrite("INSERT INTO " + m_collectionOrderTableName + " VALUES(?,?,?)", new Object[] {collectionId,(String)triple.getValue(),position});
position += 1;
m_sqlService.dbWrite("DELETE FROM " + m_collectionTableName + " WHERE " + m_collectionTableId + " = ? AND PROPERTY_NAME = '" + PROPERTY_HAS_CITATION + "' AND PROPERTY_VALUE LIKE ?", new Object[] {collectionId,(String)triple.getValue()});
}
else if(triple.getName().equals(PROP_MOST_RECENT_UPDATE))
{
try
{
edit.m_mostRecentUpdate = Long.parseLong(triple.getValue().toString());
}
catch(Exception e)
{
// do nothing
}
}
else if(triple.getName().equals(PROP_SORT_ORDER))
{
try
{
edit.setSort(triple.getValue().toString(), true);
}
catch(Exception e)
{
// do nothing
}
}
/*
* TODO: else add property??
*/
}
}
// Now add the citations into the ordering table. This has replaced the sakai:hasCitation linking mechanism.
String orderStatement = "select * from " + m_collectionOrderTableName + " where (COLLECTION_ID = ?) ORDER BY LOCATION";
List<Triple> orderTriples = m_sqlService.dbRead(orderStatement, new Object[] {collectionId}, new TripleReader());
for(Triple orderTriple : orderTriples)
{
Citation citation = retrieveCitation((String) orderTriple.getName());
citation.setPosition(Integer.parseInt((String) orderTriple.getValue()));
edit.add(citation);
}
return edit;
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#getSchema(java.lang.String)
*/
protected Schema retrieveSchema(String schemaId)
{
BasicSchema schema = (BasicSchema) ThreadLocalManager.get(schemaId);
if(schema == null)
{
String statement = "select SCHEMA_ID, PROPERTY_NAME, PROPERTY_VALUE from " + m_schemaTableName + " where (SCHEMA_ID = ?)";
Object fields[] = new Object[1];
fields[0] = schemaId;
List triples = m_sqlService.dbRead(statement, fields, new TripleReader());
if(triples.isEmpty()) {
if(CitationService.UNKNOWN_TYPE.equalsIgnoreCase(schemaId)) {
// this is just to prevent more recursion if UNKNOWN_TYPE
// schema is missing for some unknown reason
schema = new BasicSchema(CitationService.UNKNOWN_TYPE);
} else {
// this substitutes the UNKNOWN_TYPE schema if the schemaId
// is not the identifier for a known schema
schema = (BasicSchema) this.retrieveSchema(CitationService.UNKNOWN_TYPE);
}
} else {
schema = new BasicSchema(schemaId);
Iterator it = triples.iterator();
while(it.hasNext())
{
Triple triple = (Triple) it.next();
if(triple.isValid())
{
if(triple.getName().equals(PROPERTY_HAS_FIELD))
{
String fieldId = (String) triple.getValue();
BasicField field = retrieveSchemaField(schemaId, fieldId);
schema.addField(field);
}
/*
* TODO: else add property??
*/
}
}
schema.sortFields();
ThreadLocalManager.set(schema.getIdentifier(), new BasicSchema(schema));
}
}
else
{
schema = new BasicSchema(schema);
}
return schema;
}
/**
* @param fieldId
* @return
*/
protected BasicField retrieveSchemaField(String schemaId, String fieldId)
{
String statement = "select FIELD_ID, PROPERTY_NAME, PROPERTY_VALUE from " + m_schemaFieldTableName + " where (SCHEMA_ID = ? and FIELD_ID = ?)";
Object[] fields = new Object[2];
fields[0] = schemaId;
fields[1] = fieldId;
Map values = new Hashtable();
List triples = m_sqlService.dbRead(statement, fields, new TripleReader());
Iterator tripleIt = triples.iterator();
while(tripleIt.hasNext())
{
Triple triple = (Triple) tripleIt.next();
// PROPERTY_NAMESPACE namespace;
if(triple.isValid())
{
values.put(triple.getName(), triple.getValue());
}
}
String valueType = (String) values.remove(PROPERTY_VALUETYPE);
String required = (String) values.remove(PROPERTY_REQUIRED);
boolean isRequired = Boolean.TRUE.toString().equalsIgnoreCase(required);
String maxCardinality = (String) values.remove(PROPERTY_MAXCARDINALITY);
int max = 1;
if(maxCardinality != null)
{
max = new Integer(maxCardinality).intValue();
}
String minCardinality = (String) values.remove(PROPERTY_MINCARDINALITY);
int min = 0;
if(minCardinality != null)
{
min = new Integer(minCardinality).intValue();
}
BasicField field = new BasicField(fieldId, valueType, true, isRequired, min, max);
// PROPERTY_HAS_ORDER
String order = (String) values.remove(PROPERTY_HAS_ORDER);
if(order != null)
{
try
{
Integer o = new Integer(order);
field.setOrder(o.intValue());
}
catch(Exception e)
{
// couldn't get integer out of the value
}
}
// PROPERTY_NAMESPACE
String namespace = (String) values.remove(PROPERTY_NAMESPACE);
if(namespace != null)
{
field.setNamespaceAbbreviation(namespace);
}
// PROPERTY_LABEL label;
String label = (String) values.remove(PROPERTY_LABEL);
if(label != null)
{
field.setLabel(label);
}
// PROPERTY_DESCRIPTION description;
String description = (String) values.remove(PROPERTY_DESCRIPTION);
if(description != null)
{
field.setDescription(description);
}
// PROPERTY_DEFAULTVALUE defaultValue;
String defaultValue = (String) values.remove(PROPERTY_DEFAULTVALUE);
if(defaultValue == null)
{
// do nothing
}
else if(String.class.getName().equalsIgnoreCase(valueType))
{
field.setDefaultValue(defaultValue);
}
else if(Integer.class.getName().equalsIgnoreCase(valueType))
{
field.setDefaultValue(new Integer(defaultValue));
}
else if(Boolean.class.getName().equalsIgnoreCase(valueType))
{
field.setDefaultValue(new Boolean(defaultValue));
}
else if(Time.class.getName().equalsIgnoreCase(valueType))
{
field.setDefaultValue(TimeService.newTime(new Integer(defaultValue).longValue()));
}
// PROP_HAS_RIS_IDENTIFIER RIS identifier
String risIdentifier = (String) values.remove(PROP_HAS_RIS_IDENTIFIER);
if(risIdentifier != null)
{
field.setIdentifier(RIS_FORMAT, risIdentifier);
}
return field;
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#getSchemaNames()
*/
protected List retrieveSchemaList()
{
List schemaIds = (List) ThreadLocalManager.get("DbCitationStorage.listSchemas");
if(schemaIds == null)
{
String statement = "select distinct SCHEMA_ID from " + m_schemaTableName + " order by SCHEMA_ID";
schemaIds = m_sqlService.dbRead(statement, null, null);
ThreadLocalManager.set("DbCitationStorage.listSchemas", schemaIds);
}
return new Vector(schemaIds);
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#getSchemas()
*/
protected List retrieveSchemas()
{
List schemas = (List) ThreadLocalManager.get("DbCitationStorage.getSchemas");
if(schemas == null)
{
String statement = "select SCHEMA_ID, PROPERTY_NAME, PROPERTY_VALUE from " + m_schemaTableName + " order by SCHEMA_ID";
List triples = m_sqlService.dbRead(statement, null, new TripleReader());
schemas = new Vector();
BasicSchema schema = null;
String schemaId = "";
Iterator it = triples.iterator();
while(it.hasNext())
{
Triple triple = (Triple) it.next();
if(triple.isValid())
{
if(! schemaId.equals(triple.getId()))
{
schemaId = triple.getId();
schema = new BasicSchema(schemaId);
schemas.add(schema);
}
if(triple.getName().equals(PROPERTY_HAS_FIELD))
{
String fieldId = (String) triple.getValue();
BasicField field = retrieveSchemaField(schemaId, fieldId);
schema.addField(field);
}
/*
* TODO: else add property??
*/
}
}
Iterator schemaIt = schemas.iterator();
while(schemaIt.hasNext())
{
BasicSchema sch = (BasicSchema) schemaIt.next();
sch.sortFields();
}
ThreadLocalManager.set("DbCitationStorage.getSchemas", schemas);
}
List rv = new Vector();
Iterator it = schemas.iterator();
while(it.hasNext())
{
Schema schema = (Schema) it.next();
rv.add(new BasicSchema(schema));
}
schemas = rv;
return schemas;
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#updateSchema(org.sakaiproject.citation.api.Schema)
*/
protected void reviseSchema(Schema schema)
{
deleteSchema(schema);
createSchema(schema);
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#updateSchemas(java.util.Collection)
*/
protected void reviseSchemas(Collection schemas)
{
Iterator it = schemas.iterator();
while(it.hasNext())
{
Schema schema = (Schema) it.next();
reviseSchema(schema);
}
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#checkCitation(java.lang.String)
*/
protected boolean validCitation(String citationId)
{
String statement = "select " + m_citationTableId + " from " + m_citationTableName + " where ( " + m_citationTableId + " = ? )";
Object fields[] = new Object[1];
fields[0] = citationId;
List rows = m_sqlService.dbRead(statement, fields, null);
boolean found = ! rows.isEmpty();
return found;
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#checkCollection(java.lang.String)
*/
protected boolean validCollection(String collectionId)
{
String statement = "select " + m_collectionTableId + " from " + m_collectionTableName + " where (" + m_collectionTableId + " = ?)";
Object fields[] = new Object[1];
fields[0] = collectionId;
List rows = m_sqlService.dbRead(statement, fields, null);
boolean found = ! rows.isEmpty();
return found;
}
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService.Storage#checkSchema(java.lang.String)
*/
protected boolean validSchema(String schemaId)
{
String statement = "select " + m_schemaTableId + " from " + m_schemaTableName + " where (" + m_schemaTableId + " = ?)";
Object fields[] = new Object[1];
fields[0] = schemaId;
List rows = m_sqlService.dbRead(statement, fields, null);
boolean found = ! rows.isEmpty();
return found;
}
public long mostRecentUpdate(String collectionId)
{
String statement = "select PROPERTY_VALUE from " + m_collectionTableName + " where (COLLECTION_ID = ? and PROPERTY_NAME = ?)" ;
Object fields[] = new Object[2];
fields[0] = collectionId;
fields[1] = PROP_MOST_RECENT_UPDATE;
List list = m_sqlService.dbRead(statement, fields, null);
long time = 0L;
if(list == null || list.isEmpty())
{
// do nothing
}
else
{
try
{
time = Long.parseLong(list.get(0).toString());
}
catch(Exception e)
{
// do nothing
}
}
return time;
}
}
public class Triple
{
protected String m_id;
protected String m_name;
protected Object m_value;
/**
* @param id
* @param name
* @param value
*/
public Triple(String id, String name, String value)
{
super();
m_id = id;
m_name = name;
m_value = value;
}
/**
* @return the id
*/
public String getId()
{
return m_id;
}
/**
* @return the name
*/
public String getName()
{
return m_name;
}
/**
* @return the value
*/
public Object getValue()
{
return m_value;
}
/**
* @return
*/
public boolean isValid()
{
return m_id != null && m_name != null && m_value != null;
}
/**
* @param id the id to set
*/
public void setId(String id)
{
m_id = id;
}
/**
* @param name the name to set
*/
public void setName(String name)
{
m_name = name;
}
/**
* @param value the value to set
*/
public void setValue(Object value)
{
m_value = value;
}
public String toString()
{
return "[triple id = " + ((m_id == null) ? "null" : m_id)
+ " name = " + ((m_name == null) ? "null" : m_name)
+ " value = " + ((m_value == null) ? "null" : m_value.toString() + "]");
}
}
public class TripleReader implements SqlReader
{
/* (non-Javadoc)
* @see org.sakaiproject.db.api.SqlReader#readSqlResultRecord(java.sql.ResultSet)
*/
public Object readSqlResultRecord(ResultSet result)
{
Triple triple = null;
String citationId = null;
String name = null;
String value = null;
try
{
citationId = result.getString(1);
name = result.getString(2);
value = result.getString(3);
triple = new Triple(citationId, name, value);
}
catch (SQLException e)
{
M_log.debug("TripleReader: problem reading triple from result: citationId(" + citationId + ") name(" + name + ") value(" + value + ")");
return null;
}
return triple;
}
}
private static final int AUTO_FALSE = 3;
private static final int AUTO_TRUE = 2;
/* Connection management: Original auto-commit state (unknown, on, off) */
private static final int AUTO_UNKNOWN = 1;
/** Our logger. */
private static Log M_log = LogFactory.getLog(DbCitationService.class);
protected static final Pattern MULTIVALUED_PATTERN = Pattern.compile("^(.*)\\t(\\d+)$");
protected static final String PROP_SORT_ORDER = "sakai:sort_order";
protected static final String PROP_MOST_RECENT_UPDATE = "sakai:most_recent_update";
protected static final String PROP_ADDED = "sakai:added";
protected static final String PROP_DISPLAYNAME = "sakai:displayname";
protected static final String PROP_HAS_RIS_IDENTIFIER = "sakai:ris_identifier";
protected static final String PROP_HAS_URL = "sakai:has_url";
protected static final String PROP_HAS_PREFERRED_URL = "sakai:has_preferred_url";
protected static final String PROP_MEDIATYPE = "sakai:mediatype";
protected static final String PROP_URL_LABEL = "sakai:url_label";
protected static final String PROP_URL_STRING = "sakai:url_string";
protected static final String PROP_URL_ADD_PREFIX = "sakai:url_add_prefix";
protected static final String PROPERTY_NAME_DELIMITOR = "\t";
/** Configuration: to run the ddl on init or not. */
protected boolean m_autoDdl = false;
protected String m_citationTableId = "CITATION_ID";
/** Table name for citation. */
protected String m_citationTableName = "CITATION_CITATION";
protected String m_collectionTableId = "COLLECTION_ID";
/** Table name for collections. */
protected String m_collectionTableName = "CITATION_COLLECTION";
/** Table name for collection order. */
protected String m_collectionOrderTableName = "CITATION_COLLECTION_ORDER";
protected String m_schemaFieldTableId = "FIELD_ID";
protected String m_schemaFieldTableName = "CITATION_SCHEMA_FIELD";
protected String m_schemaTableId = "SCHEMA_ID";
/** Table name for schemas. */
protected String m_schemaTableName = "CITATION_SCHEMA";
/** Dependency: SqlService */
protected SqlService m_sqlService = null;
public void init()
{
try
{
// if we are auto-creating our schema, check and create
if (m_autoDdl)
{
m_sqlService.ddl(this.getClass().getClassLoader(), "sakai_citation");
M_log.info("init(): tables: " + m_collectionTableName + ", " + m_citationTableName + ", " + m_schemaTableName + ", " + m_schemaFieldTableName);
}
super.init();
}
catch (Throwable t)
{
M_log.warn("init(): ", t);
}
} // init
/* (non-Javadoc)
* @see org.sakaiproject.citation.impl.BaseCitationService#newStorage()
*/
public Storage newStorage()
{
return new DbCitationStorage();
}
/**
* Configuration: to run the ddl on init or not.
*
* @param value
* the auto ddl value.
*/
public void setAutoDdl(String value)
{
m_autoDdl = new Boolean(value).booleanValue();
}
/**
* Dependency: SqlService.
*
* @param service
* The SqlService.
*/
public void setSqlService(SqlService service)
{
m_sqlService = service;
}
/**
* Error handling: Rollback the transaction, restore auto-commit, and
* return the borrowed connection
*
* @param conn Database Connection
* @param wasCommit Original connection auto-commit state
*/
private void errorCleanup(Connection conn, int wasCommit)
{
if (conn != null)
{
try { conn.rollback(); } catch (Throwable ignore) { }
restoreAutoCommit(conn, wasCommit);
m_sqlService.returnConnection(conn);
}
}
/*
* Connection management helpers
*/
/**
* Determine auto-commit state
* @param conn Database Connection
* @return The original connection auto-commit state
*/
private int getAutoCommit(Connection conn)
{
try
{
boolean wasCommit = conn.getAutoCommit();
return wasCommit ? AUTO_TRUE : AUTO_FALSE;
}
catch (SQLException exception)
{
M_log.warn("restoreAutoCommit: " + exception);
return AUTO_UNKNOWN;
}
}
/**
* Restore auto-commit state
*
* @param conn Database Connection
* @param wasCommit Original connection auto-commit state
*/
private void restoreAutoCommit(Connection conn, int wasCommit)
{
try
{
switch (wasCommit)
{
case AUTO_TRUE:
conn.setAutoCommit(true);
break;
case AUTO_FALSE:
conn.setAutoCommit(false);
break;
case AUTO_UNKNOWN:
break;
default:
M_log.warn("restoreAutoCommit: unknown commit type: " + wasCommit);
break;
}
}
catch (Throwable throwable)
{
M_log.warn("restoreAutoCommit: " + throwable);
}
}
/**
* Form a string of (field, field, field), for sql insert statements, one for each item in the fields array, plus one before, and one after.
*
* @param before
* The first field name.
* @param values
* The extra field names, in the middle.
* @param after
* The last field name.
* @return A sql statement fragment for the insert fields.
*/
protected String insertFields(String before, String[] fields, String after)
{
StringBuilder buf = new StringBuilder();
buf.append(" (");
buf.append(before);
if (fields != null)
{
for (int i = 0; i < fields.length; i++)
{
if(i == 0 && before == null)
{
buf.append(fields[i]);
}
else
{
buf.append("," + fields[i]);
}
}
}
if(after != null)
{
buf.append("," + after);
}
buf.append(")");
return buf.toString();
}
}