/******************************************************************************* * $URL: https://source.sakaiproject.org/svn/citations/trunk/citations-impl/impl/src/java/org/sakaiproject/citation/impl/BaseCitationService.java $ * $Id: BaseCitationService.java 118211 2013-01-09 19:30:35Z jimeng@umich.edu $ * ********************************************************************************** * * Copyright (c) 2006, 2007, 2008, 2009 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.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.SortedSet; import java.util.Stack; import java.util.TreeSet; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; import java.net.URLEncoder; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.osid.repository.Asset; import org.osid.repository.Part; import org.osid.repository.PartIterator; import org.osid.repository.Record; import org.osid.repository.RecordIterator; import org.osid.repository.RepositoryException; import org.sakaiproject.citation.api.ActiveSearch; import org.sakaiproject.citation.api.Citation; import org.sakaiproject.citation.api.CitationCollection; import org.sakaiproject.citation.api.CitationIterator; import org.sakaiproject.citation.api.CitationService; import org.sakaiproject.citation.api.ConfigurationService; import org.sakaiproject.citation.api.Schema; import org.sakaiproject.citation.api.Schema.Field; import org.sakaiproject.citation.impl.openurl.ContextObject; import org.sakaiproject.citation.impl.openurl.OpenURLServiceImpl; import org.sakaiproject.component.api.ServerConfigurationService; import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.content.api.ContentEntity; import org.sakaiproject.content.api.ContentHostingService; import org.sakaiproject.content.api.ContentResource; import org.sakaiproject.content.api.ContentResourceEdit; import org.sakaiproject.content.api.InteractionAction; import org.sakaiproject.content.api.ResourceType; import org.sakaiproject.content.api.ResourceTypeRegistry; import org.sakaiproject.content.api.ResourceToolAction; import org.sakaiproject.content.api.ServiceLevelAction; import org.sakaiproject.content.api.ResourceToolAction.ActionType; import org.sakaiproject.content.util.BaseInteractionAction; import org.sakaiproject.content.util.BaseResourceAction; import org.sakaiproject.content.util.BasicSiteSelectableResourceType; //import org.sakaiproject.content.util.BaseResourceAction.Localizer; import org.sakaiproject.content.util.BaseServiceLevelAction; import org.sakaiproject.content.util.BasicResourceType; //import org.sakaiproject.content.util.BasicResourceType.Localizer; import org.sakaiproject.entity.api.Entity; import org.sakaiproject.entity.api.EntityManager; import org.sakaiproject.entity.api.HttpAccess; import org.sakaiproject.entity.api.Reference; import org.sakaiproject.entity.api.ResourceProperties; import org.sakaiproject.event.api.NotificationService; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.exception.InUseException; import org.sakaiproject.exception.OverQuotaException; import org.sakaiproject.exception.PermissionException; import org.sakaiproject.exception.ServerOverloadException; import org.sakaiproject.exception.TypeException; import org.sakaiproject.id.api.IdManager; import org.sakaiproject.javax.Filter; import org.sakaiproject.time.cover.TimeService; import org.sakaiproject.tool.api.SessionManager; import org.sakaiproject.user.api.User; import org.sakaiproject.user.api.UserDirectoryService; import org.sakaiproject.util.ResourceLoader; import org.apache.commons.lang.StringUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * * */ public abstract class BaseCitationService implements CitationService { protected boolean attemptToMatchSchema = false; protected static final List<String> AUTHOR_AS_KEY = new Vector<String>(); static { AUTHOR_AS_KEY.add( CitationCollection.SORT_BY_AUTHOR ); AUTHOR_AS_KEY.add( CitationCollection.SORT_BY_YEAR ); AUTHOR_AS_KEY.add( CitationCollection.SORT_BY_TITLE ); AUTHOR_AS_KEY.add( CitationCollection.SORT_BY_UUID ); }; protected static final List<String> YEAR_AS_KEY = new Vector<String>(); static { YEAR_AS_KEY.add( CitationCollection.SORT_BY_YEAR ); YEAR_AS_KEY.add( CitationCollection.SORT_BY_AUTHOR ); YEAR_AS_KEY.add( CitationCollection.SORT_BY_TITLE ); YEAR_AS_KEY.add( CitationCollection.SORT_BY_UUID ); }; protected static final List<String> TITLE_AS_KEY = new Vector<String>(); static { TITLE_AS_KEY.add( CitationCollection.SORT_BY_TITLE ); TITLE_AS_KEY.add( CitationCollection.SORT_BY_AUTHOR ); TITLE_AS_KEY.add( CitationCollection.SORT_BY_YEAR ); TITLE_AS_KEY.add( CitationCollection.SORT_BY_UUID ); }; public static final Map<String, String> GS_TAGS = new Hashtable<String, String>(); static { //GS_TAGS.put("rft_val_fmt", "genre"); GS_TAGS.put("rft.title", "title"); GS_TAGS.put("rft.atitle", "title"); GS_TAGS.put("rft.jtitle", "atitle"); GS_TAGS.put("rft.btitle", "atitle"); GS_TAGS.put("rft.aulast", "au"); GS_TAGS.put("rft.aufirst", "au"); GS_TAGS.put("rft.au", "au"); GS_TAGS.put("rft.pub", "publisher"); GS_TAGS.put("rft.volume", "volume"); GS_TAGS.put("rft.issue", "issue"); GS_TAGS.put("rft.pages", "pages"); GS_TAGS.put("rft.date", "date"); GS_TAGS.put("rft.issn", "id"); GS_TAGS.put("rft.isbn", "id"); } /** * */ public class BasicCitation implements Citation { /* for OpenUrl creation */ protected final static String OPENURL_VERSION = "Z39.88-2004"; protected final static String OPENURL_CONTEXT_FORMAT = "info:ofi/fmt:kev:mtx:ctx"; protected final static String OPENURL_JOURNAL_FORMAT = "info:ofi/fmt:kev:mtx:journal"; protected final static String OPENURL_BOOK_FORMAT = "info:ofi/fmt:kev:mtx:book"; protected Map m_citationProperties = null; protected Map m_urls; protected String m_citationUrl = null; protected String m_fullTextUrl = null; protected String m_id = null; protected String m_imageUrl = null; /* This only makes sense, and will only be set, in the context of a collection.*/ protected int m_position; protected Schema m_schema; protected String m_searchSourceUrl = null; protected Integer m_serialNumber = null; protected boolean m_temporary = false; protected boolean m_isAdded = false; protected String m_preferredUrl; /** * Constructs a temporary citation. */ protected BasicCitation() { m_serialNumber = nextSerialNumber(); m_temporary = true; m_citationProperties = new Hashtable(); m_urls = new Hashtable(); setType(CitationService.UNKNOWN_TYPE); } /** * Constructs a temporary citation based on an asset. * * @param asset */ protected BasicCitation(Asset asset) { m_serialNumber = nextSerialNumber(); m_temporary = true; m_citationProperties = new Hashtable(); m_urls = new Hashtable(); boolean unknownSchema = true; String title = null; Set validProperties = getValidPropertyNames(); Set multivalued = getMultivalued(); String description; /* * How to use the preferred URL? We can omit it, use it as the title * link, or supply it as the related link. * * "preferred" (below) has one of three values: false, related-link, * or title-link */ String preferredUrl = null; String preferred = m_configService.getSiteConfigUsePreferredUrls(); boolean usePreferredUrlAsTitle = preferred.equals("title-link"); boolean usePreferredUrls = !preferred.equals("false"); // assetId = asset.getId().getIdString(); try { title = asset.getDisplayName(); if (title != null) { m_citationProperties.put(Schema.TITLE, title); } description = asset.getDescription(); if (description != null) { m_citationProperties.put("abstract", description); } RecordIterator rit = asset.getRecords(); try { while (rit.hasNextRecord()) { Record record; try { record = rit.nextRecord(); preferredUrl = null; try { PartIterator pit = record.getParts(); try { while (pit.hasNextPart()) { try { Part part = pit.nextPart(); String type = part.getPartStructure().getType() .getKeyword(); if (type == null) { // continue; } else if (validProperties.contains(type)) { if (multivalued.contains(type)) { List values = (List) m_citationProperties .get(type); if (values == null) { values = new Vector(); m_citationProperties.put(type, values); } values.add(part.getValue()); } else { m_citationProperties.put(type, part.getValue()); } } /* * This type isn't described by the schema. Is * it a preferred (title link) URL? */ else if (type.equals("preferredUrl")) { preferredUrl = (String) part.getValue(); } else if (type.equals("type")) { if (m_schema == null || m_schema.getIdentifier().equals( "unknown")) { if (getSynonyms("article").contains( part.getValue().toString() .toLowerCase())) { m_schema = BaseCitationService.this .getSchema("article"); unknownSchema = false; } else if (getSynonyms("book").contains( part.getValue().toString() .toLowerCase())) { m_schema = BaseCitationService.this .getSchema("book"); unknownSchema = false; } else if (getSynonyms("chapter").contains( part.getValue().toString() .toLowerCase())) { m_schema = BaseCitationService.this .getSchema("chapter"); unknownSchema = false; } else if (getSynonyms("report").contains( part.getValue().toString() .toLowerCase())) { m_schema = BaseCitationService.this .getSchema("report"); unknownSchema = false; } else { m_schema = BaseCitationService.this .getSchema("unknown"); unknownSchema = true; } } List values = (List) m_citationProperties.get(type); if (values == null) { values = new Vector(); m_citationProperties.put(type, values); } values.add(part.getValue()); } else { } } catch (RepositoryException e) { M_log.warn("BasicCitation(" + asset + ") ", e); } } } catch (RepositoryException e) { M_log.warn("BasicCitation(" + asset + ") ", e); } } catch (RepositoryException e1) { M_log.warn("BasicCitation(" + asset + ") ", e1); } } catch (RepositoryException e2) { M_log.warn("BasicCitation(" + asset + ") ", e2); } } } catch (RepositoryException e) { M_log.warn("BasicCitation(" + asset + ") ", e); } } catch (RepositoryException e) { M_log.warn("BasicCitation(" + asset + ") ", e); } if(unknownSchema && attemptToMatchSchema) { matchSchema(); } setDefaults(); /* * Did we find a preferred URL? If so, should we use it? */ if (usePreferredUrls && (preferredUrl != null)) { String id; /* * Save the URL without a label (it'll get the default label at * render-time). This URL needs to have the prefix text added at * render time, and we'll [optionally] set it as the preferred * (or title) link. */ id = addCustomUrl("", preferredUrl, Citation.ADD_PREFIX_TEXT); if (usePreferredUrlAsTitle) { setPreferredUrl(id); } } } /** * */ protected void matchSchema() { Map pros = new Hashtable(); Map cons = new Hashtable(); List schemas = getSchemas(); Set fieldNames = this.m_citationProperties.keySet(); Iterator schemaIt = schemas.iterator(); while(schemaIt.hasNext()) { Schema schema = (Schema) schemaIt.next(); if(schema.getIdentifier().equals("unknown")) { continue; } pros.put(schema.getIdentifier(), new Counter()); cons.put(schema.getIdentifier(), new Counter()); Iterator fieldIt = fieldNames.iterator(); while(fieldIt.hasNext()) { String fieldName = (String) fieldIt.next(); Field field = schema.getField(fieldName); if(field == null) { // this indicates that data would be lost. ((Counter) cons.get(schema.getIdentifier())).increment(); } else { // this is evidence that this schema might be best fit. ((Counter) pros.get(schema.getIdentifier())).increment(); } } } // elminate schema that lose data for(Map.Entry<String, Counter> entry : ((Map<String, Counter>) cons).entrySet()) { if(entry.getValue().intValue() > 0) { pros.remove(entry.getKey()); } } Iterator prosIt = pros.keySet().iterator(); int bestScore = 0; String bestMatch = null; // Nominate "article" as first candidate if it's not blocked Object article = pros.get("article"); if(article != null) { bestScore = ((Counter) article).intValue(); bestMatch = "article"; } while(prosIt.hasNext()) { String schemaId = (String) prosIt.next(); int score = ((Counter) pros.get(schemaId)).intValue(); if(score > bestScore) { bestScore = score; bestMatch = schemaId; } } if(bestMatch != null) { m_schema = BaseCitationService.this.getSchema(bestMatch); } } /** * @param other */ public BasicCitation(BasicCitation other) { m_id = other.m_id; m_serialNumber = other.m_serialNumber; m_temporary = other.m_temporary; m_citationProperties = new Hashtable(); m_urls = new Hashtable(); setSchema(other.m_schema); copy(other); } /** * Construct a citation not marked as temporary of a particular type. * * @param mediatype */ public BasicCitation(String mediatype) { m_id = m_idManager.createUuid(); m_citationProperties = new Hashtable(); m_urls = new Hashtable(); setType(mediatype); } public BasicCitation(String citationId, Schema schema) { m_id = citationId; m_citationProperties = new Hashtable(); m_urls = new Hashtable(); setSchema(schema); } /** * Construct a citation not marked as temporary of a particular type * with a particular id. * * @param citationId * @param mediatype */ public BasicCitation(String citationId, String mediatype) { m_id = citationId; m_citationProperties = new Hashtable(); m_urls = new Hashtable(); setType(mediatype); } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#addCustomUrl(java.lang.String, * java.net.URL) */ public String addCustomUrl(String label, String url) { UrlWrapper wrapper = new UrlWrapper(label, url); String id = m_idManager.createUuid(); m_urls.put(id, wrapper); return id; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#addCustomUrl(java.lang.String, * java.net.URL, * jave.lang.String) */ public String addCustomUrl(String label, String url, String prefixRequest) { UrlWrapper wrapper = new UrlWrapper(label, url, getPrefixBoolean(prefixRequest)); String id = m_idManager.createUuid(); m_urls.put(id, wrapper); return id; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#updateCustomUrl(java.lang.String, * java.lang.String, * java.lang.String, * java.lang.String) */ public void updateCustomUrl(String urlid, String label, String url, String prefixRequest) { UrlWrapper wrapper = new UrlWrapper(label, url, getPrefixBoolean(prefixRequest)); m_urls.put(urlid, wrapper); } /* * addCustomUrl()/updateCustomUrl() helper: Convert the "prefix request * string" to a boolean value * * @param prefixRequest Prefix request text * @return true if the request is to add URL prefix */ private boolean getPrefixBoolean(String prefixRequest) { if (!Citation.ADD_PREFIX_TEXT.equals(prefixRequest) && !Citation.OMIT_PREFIX_TEXT.equals(prefixRequest)) { M_log.debug("Unexpected \"add prefix\" request: " + prefixRequest); } return Citation.ADD_PREFIX_TEXT.equals(prefixRequest); } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#addPropertyValue(java.lang.String, * java.lang.Object) */ public void addPropertyValue(String name, Object value) { getCitationProperties(); if (isMultivalued(name)) { List list = (List) this.m_citationProperties.get(name); if (list == null) { list = new Vector(); this.m_citationProperties.put(name, list); } list.add(value); } else { this.m_citationProperties.put(name, value); } } /** * * @param citation */ public void copy(Citation citation) { BasicCitation other = (BasicCitation) citation; m_citationUrl = other.m_citationUrl; m_fullTextUrl = other.m_fullTextUrl; m_imageUrl = other.m_imageUrl; m_searchSourceUrl = other.m_searchSourceUrl; m_preferredUrl = other.m_preferredUrl; m_schema = other.m_schema; if (m_citationProperties == null) { m_citationProperties = new Hashtable(); } m_citationProperties.clear(); if (other.m_citationProperties != null) { Iterator propIt = other.m_citationProperties.keySet().iterator(); while (propIt.hasNext()) { String name = (String) propIt.next(); Object obj = other.m_citationProperties.get(name); if (obj == null) { } else if (obj instanceof List) { List list = (List) obj; List copy = new Vector(); Iterator valueIt = list.iterator(); while (valueIt.hasNext()) { Object val = valueIt.next(); copy.add(val); } this.m_citationProperties.put(name, copy); } else if (obj instanceof String) { this.m_citationProperties.put(name, obj); } else { M_log.debug("BasicCitation copy constructor: property is not String or List: " + name + " (" + obj.getClass().getName() + ") == " + obj); this.m_citationProperties.put(name, obj); } } } if (m_urls == null) { m_urls = new Hashtable(); } m_urls.clear(); if (other.m_urls != null) { Iterator urlIt = other.m_urls.keySet().iterator(); while (urlIt.hasNext()) { String id = (String) urlIt.next(); UrlWrapper wrapper = (UrlWrapper) other.m_urls.get(id); // Do not want to addCustomUrl because that assigns a new, unique id to the customUrl. // This causes problems when we try to reference the preferredUrl by its id - it was // created and set in the 'other' citation //addCustomUrl(wrapper.getLabel(), wrapper.getUrl()); // instead, we store the customUrl along with it's originial id -- since this citation // is a copy of 'other', there should be no harm in doing this m_urls.put(id, wrapper); } } } /* * Simple helpers to export RIS items * prefix will most often be empty, and is used to offer an "internal label" * for stuff that gets shoved into the Notes (N1) field because there isn't * a dedicated field (e.g., Rights) * * Outputs XX - value * or * XX - prefix: value */ public void exportRisField(String rislabel, String value, StringBuilder buffer, String prefix) { // Get rid of the newlines and spaces value = value.replaceAll("\n", " "); rislabel = rislabel.trim(); // Adjust the prefix to have a colon-space afterwards, if there *is* a prefix if (prefix == null) { prefix = ""; } prefix = prefix.trim(); if (!prefix.equals("")) { prefix = prefix + ": "; } // Export it only if there's a value, or if it's an ER tag (which is by design empty) if (value != null && !value.trim().equals("") || rislabel.equals("ER")) { buffer.append(rislabel + RIS_DELIM + prefix + value + "\n"); } } /* * Again, without the prefix */ public void exportRisField(String rislabel, String value, StringBuilder buffer) { exportRisField(rislabel, value, buffer, ""); } /* * If the value is a list, iterate over it and recursively call exportRISField * */ public void exportRisField(String rislabel, List propvalues, StringBuilder buffer, String prefix) { Iterator propvaliter = propvalues.iterator(); while (propvaliter.hasNext()) { exportRisField(rislabel, propvaliter.next(), buffer, prefix); } } /* * And again, to do the dispatch */ public void exportRisField(String rislabel, Object val, StringBuilder buffer, String prefix) { if (val instanceof List) { exportRisField(rislabel, (List) val, buffer, prefix); } else { exportRisField(rislabel, (String) val.toString(), buffer, prefix); } } /* * And, finally, a dispatcher to deal with items without a prefix */ public void exportRisField(String rislabel, Object val, StringBuilder buffer) { exportRisField(rislabel, val, buffer, ""); } /* * * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#exportToRis(java.io.OutputStream) */ public void exportRis(StringBuilder buffer) throws IOException { // Get the RISType and write a blank line and the TY tag String type = "article"; if (m_schema != null) { type = m_schema.getIdentifier(); } String ristype = (String) m_RISType.get(type); if (ristype == null) { ristype = (String) m_RISType.get("article"); } exportRisField("TY", ristype, buffer); // Cycle through all the properties except for those that need // pre-processing (as listed in m_RISSpecialFields) // Deal with the "normal" fields List fields = m_schema.getFields(); Iterator iter = fields.iterator(); while (iter.hasNext()) { Field field = (Field) iter.next(); String fieldname = field.getIdentifier(); if (m_RISSpecialFields.contains(fieldname)) { continue; // Skip if this is a special field } String rislabel = field.getIdentifier(RIS_FORMAT); // SAK-16740 -- Need to skip fields if risLabel is "" (or null) if (rislabel != null && ! rislabel.trim().equals("")) { exportRisField(rislabel, getCitationProperty(fieldname, false), buffer); } } // Deal with the speical fields. /** * Dates need to be of the formt YYYY/MM/DD/other, including the * slashes even if the data is empty. Hence, we'll mostly be * producing YYYY// for date formats */ // TODO: deal with real dates. Right now, just year exportRisField("Y1", getCitationProperty(Schema.YEAR, false) + "//", buffer); // Other stuff goes into the note field -- including the note // itself of course. Iterator specIter = m_RISNoteFields.entrySet().iterator(); while (specIter.hasNext()) { Map.Entry entry = (Map.Entry) specIter.next(); String fieldname = (String) entry.getKey(); String prefix = (String) entry.getValue(); exportRisField("N1", getCitationProperty(fieldname, false), buffer, prefix); } /** * Deal with URLs. */ Iterator urlIDs = this.getCustomUrlIds().iterator(); while (urlIDs.hasNext()) { String id = urlIDs.next().toString(); try { String url = this.getCustomUrl(id); String urlLabel = this.getCustomUrlLabel(id); exportRisField("UR", url, buffer); // URL exportRisField("NT", url, buffer, urlLabel); // Note } catch (IdUnusedException e) { // do nothing } } // Write out the end-of-record identifier and an extra newline exportRisField("ER", "", buffer); buffer.append("\n"); } /* (non-Javadoc) * @see org.sakaiproject.citation.api.Citation#getCitationProperties() */ public Map getCitationProperties() { if (m_citationProperties == null) { m_citationProperties = new Hashtable(); } return m_citationProperties; } /* * (non-Javadoc) * @see org.sakaiproject.citation.api.Citation#getCitationProperty(java.lang.String) */ public Object getCitationProperty(String name) { return this.getCitationProperty(name, false); } /* * (non-Javadoc) * @see org.sakaiproject.citation.api.Citation#getCitationProperty(java.lang.String, boolean) */ public Object getCitationProperty(String name, boolean needSingleValue) { Object value = null; if(name == null) { value = ""; } else { if (m_citationProperties == null) { m_citationProperties = new Hashtable(); } value = m_citationProperties.get(name); if (value == null) { if (isMultivalued(name)) { value = new Vector(); ((List) value).add(""); } else { value = ""; } } else if (List.class.isInstance(value)) { if(needSingleValue ) { value = ((List) value).get(0); } } } return value; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#getAuthor() */ public String getCreator() { List creatorList = null; Object creatorObj = m_citationProperties.get(Schema.CREATOR); if (creatorObj == null) { creatorList = new Vector(); m_citationProperties.put(Schema.CREATOR, creatorList); } else if (creatorObj instanceof List) { creatorList = (List) creatorObj; } else if (creatorObj instanceof String) { creatorList = new Vector(); creatorList.add(creatorObj); m_citationProperties.put(Schema.CREATOR, creatorList); } String creators = ""; int count = 0; if (creatorList == null) { return creators; } StringBuilder buf = new StringBuilder(); Iterator it = creatorList.iterator(); while (it.hasNext()) { String creator = (String) it.next(); if (it.hasNext() && count > 0) { buf.append(";"); } else if (it.hasNext()) { // do nothing } else if (count > 1) { buf.append("; and "); } else if (count > 0) { buf.append(" and "); } buf.append(creator); count++; } creators = buf.toString(); if (!creators.trim().equals("") && !creators.trim().endsWith(".")) { creators = creators.trim() + ". "; } return creators; } /** * Fetch a custom (direct) URL by ID. * * @see org.sakaiproject.citation.api.Citation#getCustomUrl(java.lang.String) */ public String getCustomUrl(String id) throws IdUnusedException { UrlWrapper wrapper; StringBuilder urlBuffer; String prefix; if ((wrapper = (UrlWrapper) m_urls.get(id)) == null) { throw new IdUnusedException(id); } urlBuffer = new StringBuilder(wrapper.getUrl()); if (wrapper.addPrefix()) { if ((prefix = getUrlPrefix()) != null) { urlBuffer.insert(0, prefix); } } return urlBuffer.toString(); } /** * Fetch a custom (direct) URL by ID. The URL prefix (if applicable) * is not added. * * @see org.sakaiproject.citation.api.Citation#getUnprefixedCustomUrl(java.lang.String) */ public String getUnprefixedCustomUrl(String id) throws IdUnusedException { UrlWrapper wrapper = (UrlWrapper) m_urls.get(id); if (wrapper == null) { throw new IdUnusedException(id); } return wrapper.getUrl(); } /** * Fetch the configured URL prefix string. * @return The prefix (null if none) * * @see org.sakaiproject.citation.api.Citation#getUnprefixedCustomUrl(java.lang.String) */ public String getUrlPrefix() { return m_configService.getSiteConfigPreferredUrlPrefix(); } /** * Add prefix text to this URL? * @return true If the URL should get the prefix */ public boolean addPrefixToUrl(String id) throws IdUnusedException { UrlWrapper wrapper = (UrlWrapper) m_urls.get(id); if (wrapper == null) { throw new IdUnusedException(id); } return wrapper.addPrefix(); } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#getUrlIds() */ public List getCustomUrlIds() { List rv = new Vector(); if (!m_urls.isEmpty()) { rv.addAll(m_urls.keySet()); } return rv; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#getUrlLabel(java.lang.String) */ public String getCustomUrlLabel(String id) throws IdUnusedException { UrlWrapper wrapper = (UrlWrapper) m_urls.get(id); if (wrapper == null) { throw new IdUnusedException(id); } return wrapper.getLabel(); } public String getYear() { String yearDate = (String) getCitationProperty(Schema.YEAR, true); return yearDate; } public String getDisplayName() { String displayName = (String) getCitationProperty(Schema.TITLE, true); if (displayName == null || displayName.trim().equals("")) { displayName = "untitled"; setCitationProperty(Schema.TITLE, "untitled"); } displayName = displayName.trim(); if (displayName.length() > 0 && !displayName.endsWith(".") && !displayName.endsWith("?") && !displayName.endsWith("!") && !displayName.endsWith(",")) { displayName += "."; } return new String(displayName); } /** * Get the primary URL for this resource * * Normally, this is an OpenURL created from citation properties, but if * either the Repository OSID or the user has designated a preferred URL, * we'll use it instead. * * @return The primary URL (null if none available) */ public String getPrimaryUrl() { String url; /* * Stop now if we haven't set up any Citation properties */ if (m_citationProperties == null) { return null; } /* * Custom URL? */ if (hasPreferredUrl()) { String id = getPreferredUrlId(); try { return getCustomUrl(id); } catch (IdUnusedException exception) { M_log.warn("No matching URL for ID: " + id + ", returning an OpenURL"); } } /* * Use an OpenURL */ return getOpenurl(); } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#getFirstAuthor() */ public String getFirstAuthor() { String firstAuthor = null; List authors = (List) this.m_citationProperties.get(Schema.CREATOR); if (authors != null && !authors.isEmpty()) { firstAuthor = (String) authors.get(0); } if (firstAuthor != null) { firstAuthor = firstAuthor.trim(); } return firstAuthor; } public String getId() { if (isTemporary()) { return m_serialNumber.toString(); } return m_id; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#getOpenurl() */ public String getOpenurl() { // check citationProperties if (m_citationProperties == null) { // citation properties do not exist as yet - no OpenUrl return null; } // SAK-16886 Honor parameters "hard coded" at the end of the resolver URL String resolverUrl = m_configService.getSiteConfigOpenUrlResolverAddress(); String firstDelimiter = (resolverUrl.indexOf("?") != -1) ? "&" : "?"; String openUrlParams = getOpenurlParameters(); // return the URL-encoded string return resolverUrl + firstDelimiter + openUrlParams; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#getOpenurlParameters() */ public String getOpenurlParameters() { // check citationProperties if (m_citationProperties == null) { // citation properties do not exist as yet - no OpenUrl return ""; } ContextObject co = m_openURLService.convert(this); StringBuilder openUrl = new StringBuilder(); //openUrl.append("?"); if (co != null) { String openUrlParams = m_openURLService.toURL(co); openUrl.append(openUrlParams); } // genre needs some further work... TODO return openUrl.toString(); } /** * This only makes sense, and will only be set, in the context of a collection. */ public int getPosition() { return m_position; } public Schema getSchema() { return m_schema; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#getSource() */ public String getSource() { String place = (String) getCitationProperty("publicationLocation", true); String publisher = (String) getCitationProperty(Schema.PUBLISHER, true); String sourceTitle = (String) getCitationProperty(Schema.SOURCE_TITLE, true); String year = (String) getCitationProperty(Schema.YEAR, true); String volume = (String) getCitationProperty(Schema.VOLUME, true); String issue = (String) getCitationProperty(Schema.ISSUE, true); String pages = (String) getCitationProperty(Schema.PAGES, true); String startPage = (String) getCitationProperty("startPage", true); String endPage = (String) getCitationProperty("endPage", true); if (pages == null || pages.trim().equals("")) { pages = null; if (startPage != null && ! startPage.trim().equals("")) { pages = startPage.trim(); if (endPage != null && ! endPage.trim().equals("")) { pages += "-" + endPage; } } } String source = ""; String schemaId = "unknown"; if (m_schema != null) { schemaId = m_schema.getIdentifier(); } if ("book".equals(schemaId) || "report".equals(schemaId)) { if (place != null && !place.trim().equals("")) { source += place; } if (publisher != null && !publisher.trim().equals("")) { if (source.length() > 0) { source = source.trim() + ": "; } source += publisher; } if (year != null && ! year.trim().equals("")) { if (source.length() > 0) { source = source.trim() + ", "; } source += year; } } else if ("article".equals(schemaId)) { if (sourceTitle != null && !sourceTitle.trim().equals("")) { source += sourceTitle; if (volume != null && !volume.trim().equals("")) { source += ", " + volume; if (issue != null && !issue.trim().equals("")) { source += "(" + issue + ") "; } } } if(year != null && ! year.trim().equals("")) { source += " " + year; } if(source != null && source.length() > 1) { source = source.trim(); if(!source.endsWith(".") && !source.endsWith("?") && !source.endsWith("!") && !source.endsWith(",")) { source += ". "; } } if (pages != null && !pages.trim().equals("")) { source += pages; } if(source != null && source.length() > 1) { source = source.trim(); if(!source.endsWith(".") && !source.endsWith("?") && !source.endsWith("!") && !source.endsWith(",")) { source += ". "; } } } else if ("chapter".equals(schemaId)) { if (sourceTitle != null && !sourceTitle.trim().equals("")) { source += "In " + sourceTitle; if (pages == null) { if (startPage != null && !startPage.trim().equals("")) { source = source.trim() + ", " + startPage; if (endPage != null && !endPage.trim().equals("")) { source = source.trim() + "-" + endPage; } } } else { source = source.trim() + ", " + pages; } if (publisher != null && !publisher.trim().equals("")) { if (place != null && !place.trim().equals("")) { source += place + ": "; } source += publisher; if (year != null && ! year.trim().equals("")) { source += ", " + year; } } else if (year != null && ! year.trim().equals("")) { source += " " + year; } } } else { if (sourceTitle != null && ! sourceTitle.trim().equals("")) { source += sourceTitle; if (volume != null && ! volume.trim().equals("")) { source += ", " + volume; if (issue != null && !issue.trim().equals("")) { source += "(" + issue + ") "; } } if (pages == null) { if (startPage != null && !startPage.trim().equals("")) { source += startPage; if (endPage != null && !endPage.trim().equals("")) { source += "-" + endPage; } } } else { if (source.length() > 0) { source += ". "; } source += pages + ". "; } } else if (publisher != null && ! publisher.trim().equals("")) { if (place != null && ! place.trim().equals("")) { source += place + ": "; } source += publisher; if (year != null && ! year.trim().equals("")) { source += ", " + year; } } } if (source.length() > 1 && !source.endsWith(".") && !source.endsWith("?") && !source.endsWith("!") && !source.endsWith(",")) { source = source.trim() + ". "; } if( source.trim().endsWith( ".." ) ) { source = source.substring( 0, source.length()-2 ); } return source; } public String getAbstract() { if ((m_citationProperties != null) && (m_citationProperties.get( "abstract" ) != null)) { String abstractText = m_citationProperties.get("abstract").toString().trim(); if (abstractText.length() > 0) { return abstractText; } } return null; } public String getSubjectString() { Object subjects = getCitationProperty( "subject", false ); if ( subjects instanceof List ) { List subjectList = ( List ) subjects; ListIterator subjectListIterator = subjectList.listIterator(); StringBuilder subjectStringBuf = new StringBuilder(); while ( subjectListIterator.hasNext() ) { subjectStringBuf.append( ((String)subjectListIterator.next()).trim() + ", " ); } String subjectString = subjectStringBuf.substring( 0, subjectStringBuf.length() - 2 ); if ( subjectString.equals("") ) { return null; } else { return subjectString; } } else { return null; } } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#hasUrls() */ public boolean hasCustomUrls() { return m_urls != null && !m_urls.isEmpty(); } public boolean hasPropertyValue(String fieldId) { return hasCitationProperty(fieldId); } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#importFromRis(java.io.InputStream) */ public void importFromRis(InputStream ris) throws IOException { // TODO Auto-generated method stub } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#importFromRisList(java.util.List) */ public boolean importFromRisList(List risImportList) { Log logger = LogFactory.getLog(BasicCitation.class); String currentLine = null; // The active line being parsed from the list (e.g. "TY - BOOK") String RIScode = null; // The RIS Code (e.g. "TY" for "TY - BOOK") String RISvalue = null; // The RIS Value (e.g. "BOOK" for "TY - BOOK") Schema schema = null; // The Citations Helper Schema to use based on the TY RIS field String schemaName = null; // The name/string of the schema used to lookup the schema List Fields = null; // This holds the mapped fields for a particular Schema Field tempField = null; // This holds the current field being evaluated while iterating through // Fields Iterator iter = null; // The iterator used to boogie through the Schema Fields boolean noFieldMapping = true; // Used to maintain/exit the tag lookup while loop String[] RIScodes = null; // This holds the RISCodes valid for a given schema String urlId = null; // Used to set the preferred URL String continueTag = null; // used to track EndNote continuation lines. int delimiterIndex = 0; // used to find the index of the hyphen to separate RIScode from RISvalue logger.debug("importFromRisList: In importFromRisList. List size is " + risImportList.size()); // process loop that iterates list size many times for(int i=0; i< risImportList.size(); i++) { // get current RIS line String dirtyString = (String) risImportList.get(i); currentLine = dirtyString.replaceAll("[\uFEFF-\uFFFF]", ""); currentLine = currentLine.trim(); logger.debug("importFromRisList: currentLine = " + currentLine); // If the RIS line is less than 4, it isn't really a valid line. Set some default values // that we know won't be processed for this line. if (currentLine.length() < 4) { RIScode = "CODENOTFOUND"; RISvalue = ""; } else { // get the RIS code // New parsing code 2008-09 based on first delimiter not index in String delimiterIndex = currentLine.indexOf('-'); // if we found a hyphen if (delimiterIndex != -1) { RIScode = currentLine.substring(0, delimiterIndex).trim(); // get substring starting with hyphen. This guarantees that we at least have a // string of length 1 for processing RISvalue = currentLine.substring(delimiterIndex).trim(); // if RISvalue's length is greater than 1 that means we have more than the hyphen for the // string. We then discard the hyphen (1st character) if (RISvalue.length() > 1) { RISvalue = RISvalue.substring(1); } else { RISvalue = ""; } } else { RIScode = "CODENOTFOUND"; RISvalue = ""; } logger.debug("importFromRisList: substr value = " + RISvalue); } // Trim the value RISvalue = RISvalue.trim(); // The RIS code TY must be the first entry is a RIS record. This sets the Schema type. if (i == 0) { if (! RIScode.equalsIgnoreCase("TY")) { logger.debug("importFromRisList: FALSE - 1st entry in RIS must be TY. It isn't it is " + RISvalue); return false; // TY MUST be the first entry in a RIS citation } else // process the schema { // RIS resource type forced mappings if (RISvalue.equalsIgnoreCase("NEWS") || RISvalue.equalsIgnoreCase("MGZN")) { logger.debug("importFromRisList: force mapping NEWS or MGZN resource type to JOUR"); RISvalue = "JOUR"; } logger.debug("importFromRisList: size of m_RISTypeInverse = " + m_RISTypeInverse.size()); logger.debug("importFromRisList: RISvalue before schemaName = " + RISvalue); // get the Schema String name that we need to use for Schema look up from // the map m_RISTypeInverse using the RISvalue for RIScode "TY"; schemaName = (String) m_RISTypeInverse.get(RISvalue); // If we couldn't find a valid schema name mapping, set the name to "unknown" if (schemaName == null) { logger.debug("importFromRisList: Unknown Schema Name = " + RISvalue + ". Setting schemeName to 'unknown'"); schemaName = "unknown"; } logger.debug("importFromRisList: Schema Name = " + schemaName); // Lookup the Schema based on the Schema string gotten from the reverse map schema = BaseCitationService.this.getSchema(schemaName); logger.debug("importFromRisList: Retrieved Schema Name = " + schema.getIdentifier()); setSchema(schema); } // end else (else processes RIScode == "TY") } // end if i == 0 else // i > 0 so we are on a line other than the first line of the RIS record. Let's process the RIS entries after the first mandatory TY/Schema code { if (RIScode.equalsIgnoreCase("ER")) // RIScode "ER" signifies the end of a citation record { logger.debug("importFromRisList: Read an ER. End of citation."); return true; // ER signals end of citation } // end of citation // Get all the valid RIS fields for this particular schema type Fields = schema.getFields(); iter = Fields.iterator(); noFieldMapping = true; while (iter.hasNext() && noFieldMapping) { tempField = (Field) iter.next(); // We found that this field is a valid field for this schema RIScodes = tempField.getIdentifierComplex(RIS_FORMAT); for(int j=0; j< RIScodes.length && noFieldMapping; j++) { // Need Trim in case RIS complex value has a space after the delimiter // (e.g. "BT, T1" vs "BT","T1") if (RIScode.equalsIgnoreCase(RIScodes[j])) { noFieldMapping = false; continueTag = null; logger.debug("importFromRisList: Found field mapping"); } } // end for j (loop through complex RIS codes) } // end while if (noFieldMapping) // couldn't find the field mapping { logger.debug("importFromRisList: Cannot find field mapping for RIScode " + RIScode + " for Schema = " + schema); // recompute hyphen location for KWTag check. Computation earlier may have gotten mangled delimiterIndex = currentLine.indexOf('-'); if (delimiterIndex == -1) { RIScode = "CODENOTFOUND"; } else { RIScode = currentLine.substring(0, delimiterIndex).trim(); } if (RIScode.equalsIgnoreCase("UR")) { urlId = addCustomUrl("", RISvalue); setPreferredUrl(urlId); continueTag = RIScode.toUpperCase(); logger.debug("importFromRisList: set preferred url to " + urlId + " which is " + RISvalue); } else if (continueTag != null && (RIScode.length() != 2) ) // continuation and not a possible RIScode { logger.debug("importFromRisList: continuation of tag found (EndNote oddity). Hacking tag and resending line through the import system"); risImportList.set(i, continueTag + " - " + currentLine); i = i-1; } } // end if noFieldMapping (field not found) else // ! noFieldMapping. We found a field in the Schema { logger.debug("importFromRisList: Field mapping is " + tempField.getIdentifier() + " => " + RISvalue); if (RIScode.equalsIgnoreCase("KW")) continueTag = RIScode.toUpperCase(); // We found a mapping. Set the citation property. setCitationProperty(tempField.getIdentifier(), RISvalue); // SAK-16949 -- If we have a date, we may need to extract and save // the year as well. // if (RIScode.equalsIgnoreCase("Y1") || RIScode.equalsIgnoreCase("PY")) { if (!schemaName.equalsIgnoreCase("electronic") || !schemaName.equalsIgnoreCase("proceed") || !schemaName.equalsIgnoreCase("thesis")) { setYearProperty(RISvalue); } } } // end else which means we found the mapping } // end else of i == 0 } // end for i // if we got here, the record wasn't properly formatted with an "ER" record (or other issues). logger.debug("importFromRisList: FALSE - End of Input. Citation not added."); return false; } // end ImportFromRisList /* * Set the year value. This is based on a provided RIS date: * * YYYY/MM/DD/Comment * * We reformat the date to reflect the ISO format: * * YYYY-MM-DD */ private void setDateProperty(String date) { StringBuilder normalized; String[] components; /* * Save the date "as is". We'll normalize and [possibly] save again. */ setCitationProperty("date", date); if (date.length() < 4) return; normalized = new StringBuilder(); components = date.split("/"); /* * Year */ if (components.length == 0) return; for (int i = 0; i < 4; i++) { char c = components[0].charAt(i); if (!Character.isDigit(c)) return; normalized.append(c); } /* * Month */ if (components.length == 1) { setCitationProperty("date", normalized.toString()); return; } if (components[1].length() == 2) { normalized.append("-"); for (int i = 0; i < 2; i++) { char c = components[1].charAt(i); if (Character.isDigit(c)) { normalized.append(c); } } } /* * Day */ if (components.length == 2) { if (normalized.length() < 7) { normalized.setLength(4); } setCitationProperty("date", normalized.toString()); return; } if (components[2].length() == 2) { normalized.append("-"); for (int i = 0; i < 2; i++) { char c = components[2].charAt(i); if (Character.isDigit(c)) { normalized.append(c); } } if (normalized.length() < 10) { normalized.setLength(((normalized.length() < 7) ? 4 : 7)); } } /* * Save the normalized date */ setCitationProperty("date", normalized.toString()); /* * Is there a note (and can we save it)? */ if (components.length == 3) return; /* * Discard the comment field for now */ } /* * Set the 4 digit year value. This is based on a provided date. We * assume RIS or ISO forrmatting, where the first four digits specify * a year. Specifically: * * YYYY/MM/DD/comment (RIS) * YYYY-MM-DD (ISO) * YYYY (what we usually see in practice) */ private void setYearProperty(String date) { StringBuilder year; if (date.length() < 4) return; year = new StringBuilder(); for (int i = 0; i < 4; i++) { char c = date.charAt(i); if (!Character.isDigit(c)) return; year.append(c); } setCitationProperty(Schema.YEAR, year.toString()); } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#isAdded() */ public boolean isAdded() { return this.m_isAdded; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#isMultivalued(java.lang.String) */ public boolean isMultivalued(String fieldId) { boolean isMultivalued = false; if (isSchemaLimited(fieldId)) { isMultivalued = isSchemaMultivalued(fieldId); } else { isMultivalued = isCurrentlyMultivalued(fieldId); // But if adding, then convert? } return isMultivalued; } /** * Checks if the field is currently multivalued. * This doesn't consult the schema, but looks what's actually stored. * @param fieldId Field name. * @return <code>true</code> if the field is multivalued. */ protected boolean isCurrentlyMultivalued(String fieldId) { // Don't use getCitationProperty as it ends up being recursive return (m_citationProperties.get(fieldId) instanceof List); } /** * Should the field be limited to a single value. * @param fieldId * @return */ protected boolean isSchemaMultivalued(String fieldId) { // No check for m_schema being null as you should check isSchemaLimited first Field field = m_schema.getField(fieldId); return (field != null && field.isMultivalued()); } /** * @return */ public boolean isTemporary() { return m_temporary; } protected boolean isSchemaLimited(String fieldId) { return m_schema != null && m_schema.getField(fieldId) != null; } public List listCitationProperties() { if (m_citationProperties == null) { m_citationProperties = new Hashtable(); } return new Vector(m_citationProperties.keySet()); } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#setAdded() */ public void setAdded(boolean added) { this.m_isAdded = added; } public void setCitationProperty(String name, Object value) { if (m_citationProperties == null) { m_citationProperties = new Hashtable(); } if (isMultivalued(name)) { List list = (List) m_citationProperties.get(name); if (list == null) { list = new Vector(); m_citationProperties.put(name, list); } if (value != null) { list.add(value); } } else { if (value == null) { m_citationProperties.remove(name); } else { Object newValue = value; // Make value multivalued if possible. // Only do this on setCitation. if (!isSchemaLimited(name)) { if (hasCitationProperty(name)) { Object existingValue = m_citationProperties.get(name); List list = new Vector(); list.add(existingValue); list.add(value); newValue = list; } } m_citationProperties.put(name, newValue); } } } public boolean hasCitationProperty(String fieldId) { Object val = m_citationProperties.get(fieldId); boolean hasValue = val != null; if (hasValue) { if (val instanceof List) { List list = (List) val; hasValue = !list.isEmpty(); } } return hasValue; } protected void setDefaults() { if (m_schema != null) { List fields = m_schema.getFields(); Iterator it = fields.iterator(); while (it.hasNext()) { Field field = (Field) it.next(); if (field.isRequired()) { Object value = field.getDefaultValue(); if (value == null) { // do nothing -- there's no value to set } else if (field.isMultivalued()) { List current_values = (List) this.getCitationProperty(field .getIdentifier(), false); if (current_values.isEmpty()) { this.setCitationProperty(field.getIdentifier(), value); } } else if (this.getCitationProperty(field.getIdentifier(), false) == null) { setCitationProperty(field.getIdentifier(), value); } } } } } public void setDisplayName(String name) { if (name == null || name.trim().equals("")) { addPropertyValue(Schema.TITLE, "untitled"); } else { addPropertyValue(Schema.TITLE, name); } } /** * This only makes sense, and will only be set, in the context of a collection. */ public void setPosition(int position) { this.m_position = position; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Citation#setSchema(org.sakaiproject.citation.api.Schema) */ public void setSchema(Schema schema) { this.m_schema = schema; setDefaults(); } protected void setType(String mediatype) { Schema schema = m_storage.getSchema(mediatype); if (schema == null) { schema = m_storage.getSchema(CitationService.UNKNOWN_TYPE); } setSchema(schema); } public String toString() { return "BasicCitation: " + this.m_id; } public void updateCitationProperty(String name, List values) { // what if "name" is not a valid field in the schema?? if (m_citationProperties == null) { m_citationProperties = new Hashtable(); } if (isMultivalued(name)) { List list = (List) m_citationProperties.get(name); if (list == null) { list = new Vector(); m_citationProperties.put(name, list); } list.clear(); if (values != null) { list.addAll(values); } } else { if (values == null || values.isEmpty()) { m_citationProperties.remove(name); } else { m_citationProperties.put(name, values.get(0)); } } } public String getPreferredUrlId() { return this.m_preferredUrl; } public boolean hasPreferredUrl() { return this.m_preferredUrl != null; } public void setPreferredUrl(String urlid) { if(urlid == null) { this.m_preferredUrl = null; } else if(this.m_urls.containsKey(urlid)) { this.m_preferredUrl = urlid; } } } // BaseCitationService.BasicCitation /** * */ public class BasicCitationCollection implements CitationCollection { protected final Comparator DEFAULT_COMPARATOR= new BasicCitationCollection.PositionComparator(); public class MultipleKeyComparator implements Comparator { protected List<String> m_keys = new Vector<String>(); protected boolean m_ascending = true; public MultipleKeyComparator(List<String> keys, boolean ascending) { m_keys.addAll(keys); } public MultipleKeyComparator( MultipleKeyComparator mkc ) { this.m_keys = mkc.m_keys; this.m_ascending = mkc.m_ascending; } /* (non-Javadoc) * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */ public int compare(Object arg0, Object arg1) { int rv = 0; if (!(arg0 instanceof String) || !(arg1 instanceof String)) { throw new ClassCastException(); } Object obj0 = m_citations.get(arg0); Object obj1 = m_citations.get(arg1); if (!(obj0 instanceof Citation) || !(obj1 instanceof Citation)) { throw new ClassCastException(); } Citation cit0 = (Citation) obj0; Citation cit1 = (Citation) obj1; Iterator keyIt = m_keys.iterator(); while(rv == 0 && keyIt.hasNext()) { String key = (String) keyIt.next(); if(CitationCollection.SORT_BY_TITLE.equalsIgnoreCase(key)) { /* String title0 = cit0.getDisplayName().toLowerCase(); String title1 = cit1.getDisplayName().toLowerCase(); */ String title0 = ((String)cit0.getCitationProperty( Schema.TITLE, true )).toLowerCase(); String title1 = ((String)cit1.getCitationProperty( Schema.TITLE, true )).toLowerCase(); if (title0 == null) { title0 = ""; } if (title1 == null) { title1 = ""; } rv = m_ascending ? title0.compareTo(title1) : title1.compareTo(title0); } else if(CitationCollection.SORT_BY_AUTHOR.equalsIgnoreCase(key)) { String author0 = cit0.getCreator().toLowerCase(); String author1 = cit1.getCreator().toLowerCase(); if (author0 == null) { author0 = ""; } if (author1 == null) { author1 = ""; } rv = m_ascending ? author0.compareTo(author1) : author1.compareTo(author0); } else if(CitationCollection.SORT_BY_YEAR.equalsIgnoreCase(key)) { String year0 = cit0.getYear(); String year1 = cit1.getYear(); if (year0 == null) { year0 = ""; } if (year1 == null) { year1 = ""; } rv = m_ascending ? year0.compareTo(year1) : year1.compareTo(year0); } else if( CitationCollection.SORT_BY_UUID.equalsIgnoreCase( key ) ) { // not considering m_ascending for ids because they are random alpha-numeric strings rv = cit0.getId().compareTo(cit1.getId()); } } return rv; } public void addKey(String key) { m_keys.add(key); } } public class AuthorComparator extends MultipleKeyComparator { /** * @param ascending */ public AuthorComparator(boolean ascending) { super(AUTHOR_AS_KEY, ascending); } } public class YearComparator extends MultipleKeyComparator { /** * @param ascending */ public YearComparator(boolean ascending) { super(YEAR_AS_KEY, ascending); } } // end class DateComparator public class PositionComparator implements Comparator { public int compare(Object arg0, Object arg1) { int rv = 0; if (!(arg0 instanceof String) || !(arg1 instanceof String)) { throw new ClassCastException(); } Object obj0 = m_citations.get(arg0); Object obj1 = m_citations.get(arg1); if (!(obj0 instanceof Citation) || !(obj1 instanceof Citation)) { throw new ClassCastException(); } Citation cit0 = (Citation) obj0; Citation cit1 = (Citation) obj1; if(cit0.getPosition() > cit1.getPosition()) return 1; else if(cit0.getPosition() == cit1.getPosition()) return 0; else return -1; } } // end class PositionComparator public class BasicIterator implements CitationIterator { protected List listOfKeys; // This is the firstItem on a given rendered page protected int firstItem; // This is the item where next() returns and increments. At // the start of rendering a given page nextItem = firstItem and // increments until lastItem protected int nextItem; // This is the lastitem on a given rendered page protected int lastItem; public BasicIterator() { checkForUpdates(); this.listOfKeys = new Vector(m_order); this.firstItem = 0; setIndexes(); } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationIterator#getPageSize() */ public int getPageSize() { // TODO Auto-generated method stub return m_pageSize; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationIterator#hasNext() */ public boolean hasNext() { boolean hasNext = false; if (m_ascending) { hasNext = this.nextItem < this.lastItem && this.nextItem < this.listOfKeys.size(); } else { hasNext = this.nextItem > this.lastItem && this.nextItem > 0; } return hasNext; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationIterator#hasNextPage() */ public boolean hasNextPage() { boolean hasNextPage = false; if (m_ascending) hasNextPage = this.firstItem + m_pageSize < this.listOfKeys.size(); else hasNextPage = this.firstItem - m_pageSize >= 0; return hasNextPage; // return m_pageSize * (startPage + 1) < this.listOfKeys.size(); } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationIterator#hasPreviousPage() */ public boolean hasPreviousPage() { boolean hasPreviousPage = false; if (m_ascending) hasPreviousPage = this.firstItem > 0; else hasPreviousPage = this.firstItem + m_pageSize < this.listOfKeys.size(); return hasPreviousPage; // return this.startPage > 0; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationIterator#next() */ public Object next() { Object item = null; if (m_ascending) { if (this.nextItem >= this.lastItem || this.nextItem >= listOfKeys.size()) { throw new NoSuchElementException(); } item = m_citations.get(listOfKeys.get(this.nextItem++)); } else { if (this.nextItem <= this.lastItem || this.nextItem <= 0) { throw new NoSuchElementException(); } item = m_citations.get(listOfKeys.get(this.nextItem--)); } return item; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationIterator#nextPage() */ public void nextPage() { if (m_ascending) { this.firstItem = this.firstItem + m_pageSize; } else { this.firstItem = this.firstItem - m_pageSize; } setIndexes(); } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationIterator#previousPage() */ public void previousPage() { if (m_ascending) { this.firstItem = this.firstItem - m_pageSize; } else { this.firstItem = this.firstItem + m_pageSize; } setIndexes(); } /* * (non-Javadoc) * * @see java.util.Iterator#remove() */ public void remove() { throw new UnsupportedOperationException(); } protected void setIndexes() { this.nextItem = this.firstItem; if (m_ascending) { this.lastItem = Math.min(this.listOfKeys.size(), this.nextItem + m_pageSize); } else { this.lastItem = Math.max(0, this.nextItem - m_pageSize); } } // end setIndexes() /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationIterator#setSort(java.util.Comparator) */ public void setOrder(Comparator comparator) { m_comparator = comparator; if (comparator == null) { } else { Collections.sort(this.listOfKeys, m_comparator); } this.firstItem = 0; setIndexes(); } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationIterator#setPageSize(int) */ public void setPageSize(int size) { if (size > 0) { // So that resizing the page at the start of a list (say 11-20) // with a new size of 20... gives us 1-20 not 11-30 if (this.lastItem <= size) { this.firstItem = 0; } this.lastItem = this.firstItem + size; if (this.lastItem >= this.listOfKeys.size()) this.lastItem = this.listOfKeys.size() - 1; m_pageSize = size; setIndexes(); } // end if size > 0 } // end setPageSize() public int getStart() { return this.firstItem; } public int getEnd() { return this.lastItem; } public void setStart(int i) { if (i >= 0 && i < this.listOfKeys.size()) { this.firstItem = i; setIndexes(); } } // end setStart() } // end class BasicIterator public class TitleComparator extends MultipleKeyComparator { /** * @param ascending */ public TitleComparator(boolean ascending) { super(TITLE_AS_KEY, ascending); } } protected Map<String, Citation> m_citations = new Hashtable<String, Citation>(); protected Comparator m_comparator = DEFAULT_COMPARATOR; protected String m_sortOrder; protected SortedSet<String> m_order; protected int m_pageSize = DEFAULT_PAGE_SIZE; protected String m_description; protected String m_id; protected String m_title; protected boolean m_temporary = false; protected Integer m_serialNumber; protected ActiveSearch m_mySearch; protected boolean m_ascending = true; protected long m_mostRecentUpdate = 0L; public BasicCitationCollection() { m_id = m_idManager.createUuid(); } /** * @param b */ public BasicCitationCollection(boolean temporary) { m_order = new TreeSet<String>(m_comparator); m_temporary = temporary; if (temporary) { m_serialNumber = nextSerialNumber(); } else { m_id = m_idManager.createUuid(); } } public BasicCitationCollection(Map attributes, List citations) { m_id = m_idManager.createUuid(); m_order = new TreeSet<String>(m_comparator); if (citations != null) { Iterator citationIt = citations.iterator(); while (citationIt.hasNext()) { this.add((Citation) citationIt.next()); } } } /** * @param collectionId */ public BasicCitationCollection(String collectionId) { m_id = collectionId; m_order = new TreeSet(m_comparator); } public void add(Citation citation) { //checkForUpdates(); if (!this.m_citations.keySet().contains(citation.getId())) { // Set this citation's position to the end. Used by the position // comparator and the reordering screen. citation.setPosition(m_citations.size() + 1); this.m_citations.put(citation.getId(), citation); } if(!this.m_order.contains(citation.getId())) { this.m_order.add(citation.getId()); } } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationCollection#addAll(org.sakaiproject.citation.api.CitationCollection) */ public void addAll(CitationCollection other) { checkForUpdates(); if(this.m_order == null) { this.m_order = new TreeSet<String>(); } for(String key : ((BasicCitationCollection) other).m_order ) { try { Citation citation = other.getCitation(key); this.add(citation); } catch (IdUnusedException e) { M_log.debug("BasicCitationCollection.addAll citationId (" + key + ") in m_order but not in m_citations; collectionId: " + other.getId()); } } } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationCollection#clear() */ public void clear() { this.m_order.clear(); this.m_citations.clear(); } public boolean contains(Citation citation) { checkForUpdates(); return this.m_citations.containsKey(citation.getId()); } protected void copy(BasicCitationCollection other) { checkForUpdates(); this.m_ascending = other.m_ascending; /* * Get new instance of comparator */ if( other.m_comparator instanceof MultipleKeyComparator ) { this.m_comparator = new MultipleKeyComparator( (MultipleKeyComparator)other.m_comparator ); } else { // default to title, ascending this.m_comparator = new MultipleKeyComparator( TITLE_AS_KEY, true ); } set(other); } public void exportRis(StringBuilder buffer, List<String> citationIds) throws IOException { checkForUpdates(); // output "header" info to buffer // Iterate over citations and output to ostream for( String citationId : citationIds ) { Citation citation = (Citation) this.m_citations.get(citationId); if (citation != null) { citation.exportRis(buffer); } } } /** * Compute an alternate root for a reference, based on the root * property. * * @param rootProperty * The property name. * @return The alternate root, or "" if there is none. */ protected String getAlternateReferenceRoot(String rootProperty) { // null means don't do this if (rootProperty == null || rootProperty.trim().equals("")) { return ""; } // make sure it start with a separator and does not end with one if (!rootProperty.startsWith(Entity.SEPARATOR)) { rootProperty = Entity.SEPARATOR + rootProperty; } if (rootProperty.endsWith(Entity.SEPARATOR)) { rootProperty = rootProperty .substring(0, rootProperty.length() - SEPARATOR.length()); } return rootProperty; } public Citation getCitation(String citationId) throws IdUnusedException { checkForUpdates(); Citation citation = (Citation) m_citations.get(citationId); if (citation == null) { throw new IdUnusedException(citationId); } return citation; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationCollection#getCitations() */ public List getCitations() { checkForUpdates(); List citations = new Vector(); if (m_citations == null) { m_citations = new Hashtable<String, Citation>(); } if(m_order == null) { m_order = new TreeSet<String>(); } Iterator keyIt = this.m_order.iterator(); while (keyIt.hasNext()) { String key = (String) keyIt.next(); Object citation = this.m_citations.get(key); if (citation != null) { citations.add(citation); } } return citations; } public CitationCollection getCitations(Comparator c) { checkForUpdates(); // TODO Auto-generated method stub return null; } public CitationCollection getCitations(Comparator c, Filter f) { checkForUpdates(); // TODO Auto-generated method stub return null; } public CitationCollection getCitations(Filter f) { checkForUpdates(); // TODO Auto-generated method stub return null; } public CitationCollection getCitations(Map properties) { checkForUpdates(); // TODO Auto-generated method stub return null; } // public Citation remove(int index) // { // // TODO // return null; // } // // public Citation remove(Map properties) // { // // TODO Auto-generated method stub // return null; // } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationCollection#getDescription() */ public String getDescription() { checkForUpdates(); return m_description; } public String getId() { return this.m_id; } @Override public Date getLastModifiedDate() { checkForUpdates(); return new Date(this.m_mostRecentUpdate); } public ResourceProperties getProperties() { // TODO Auto-generated method stub return null; } // public void sort(Comparator c) // { // // TODO Auto-generated method stub // // } public String getReference() { return getReference(null); } public String getReference(String rootProperty) { return m_relativeAccessPoint + getAlternateReferenceRoot(rootProperty) + Entity.SEPARATOR + getId(); } /* (non-Javadoc) * @see org.sakaiproject.citation.api.CitationCollection#getSaveUrl() */ public String getSort() { if (m_sortOrder == null) m_sortOrder = this.SORT_BY_DEFAULT_ORDER; return m_sortOrder; } /* (non-Javadoc) * @see org.sakaiproject.citation.api.CitationCollection#getSaveUrl() */ public String getSaveUrl() { String url = m_serverConfigurationService.getServerUrl() + "/savecite/" + this.getId() + "/"; return url; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationCollection#getTitle() */ public String getTitle() { checkForUpdates(); return m_title; } public String getUrl() { return getUrl(null); } public String getUrl(String rootProperty) { return getAccessPoint(false) + getAlternateReferenceRoot(rootProperty) + Entity.SEPARATOR + getId(); } public boolean isEmpty() { checkForUpdates(); return this.m_citations.isEmpty(); } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationCollection#iterator() */ public CitationIterator iterator() { checkForUpdates(); return new BasicIterator(); } // public Iterator iterator() // { // // TODO Auto-generated method stub // return null; // } // // // public int lastIndexOf(Citation item) // { // // TODO Auto-generated method stub // return 0; // } // // public boolean move(int from, int to) // { // // TODO Auto-generated method stub // return false; // } // // public boolean moveToBack(int index) // { // // TODO Auto-generated method stub // return false; // } // // public boolean moveToFront(int index) // { // // TODO Auto-generated method stub // return false; // } // public boolean remove(Citation item) { checkForUpdates(); boolean success = true; this.m_order.remove(item.getId()); Object obj = this.m_citations.remove(item.getId()); if (obj == null) { success = false; } return success; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationCollection#saveCitation(org.sakaiproject.citation.api.Citation) */ public void saveCitation(Citation citation) { //checkForUpdates(); // m_storage.saveCitation(citation); save(citation); } /** * * @param comparator */ public void setSort(Comparator comparator) { checkForUpdates(); this.m_comparator = comparator; SortedSet oldSet = this.m_order; this.m_order = new TreeSet<String>(this.m_comparator); this.m_order.addAll(oldSet); } /** * * @param sortBy * @param ascending */ public void setSort(String sortBy, boolean ascending) { m_ascending = ascending; String status = "UNSET"; if (sortBy == null || sortBy.equalsIgnoreCase(SORT_BY_DEFAULT_ORDER)) { this.m_comparator = null; } else if (sortBy.equalsIgnoreCase(SORT_BY_AUTHOR)) { this.m_comparator = new AuthorComparator(ascending); status = "AUTHOR SET"; } else if (sortBy.equalsIgnoreCase(SORT_BY_TITLE)) { this.m_comparator = new TitleComparator(ascending); status = "TITLE SET"; } else if (sortBy.equalsIgnoreCase(SORT_BY_YEAR)) { this.m_comparator = new YearComparator(ascending); status = "YEAR SET"; } else if (sortBy.equalsIgnoreCase(SORT_BY_POSITION)) { this.m_comparator = new PositionComparator(); status = "POSITION SET"; } if (this.m_comparator != null) { this.m_sortOrder = sortBy; SortedSet oldSet = this.m_order; this.m_order = new TreeSet<String>(this.m_comparator); this.m_order.addAll(oldSet); } } // end setSort(String, boolean) public int size() { checkForUpdates(); return m_order.size(); } public String toString() { return "BasicCitationCollection: " + this.m_id; } public Element toXml(Document doc, Stack stack) { // TODO Auto-generated method stub return null; } protected void checkForUpdates() { if(this.m_mostRecentUpdate < m_storage.mostRecentUpdate(this.m_id)) { CitationCollection edit = m_storage.getCollection(this.m_id); if (edit == null) { } else { set((BasicCitationCollection) edit); } } } /** * copy * @param other */ protected void set(BasicCitationCollection other) { this.m_description = other.m_description; // this.m_comparator = other.m_comparator; this.m_serialNumber = other.m_serialNumber; this.m_pageSize = other.m_pageSize; this.m_temporary = other.m_temporary; this.m_title = other.m_title; if(this.m_citations == null) { this.m_citations = new Hashtable<String, Citation>(); } this.m_citations.clear(); if(this.m_order == null) { this.m_order = new TreeSet<String>(this.m_comparator); } this.m_order.clear(); Iterator it = other.m_citations.keySet().iterator(); while(it.hasNext()) { String citationId = (String) it.next(); BasicCitation oldCitation = (BasicCitation) other.m_citations.get(citationId); BasicCitation newCitation = new BasicCitation(); try { newCitation.copy(oldCitation); newCitation.m_id = oldCitation.m_id; newCitation.m_temporary = false; this.saveCitation(newCitation); this.add(newCitation); } catch(Exception e) { M_log.warn("copy(" + oldCitation.getId() + ") ==> " + newCitation.getId(), e); } } this.m_mostRecentUpdate = TimeService.newTime().getTime(); } } // BaseCitationService.BasicCitationCollection /** * */ public class BasicField implements Field { protected Object defaultValue; protected String description; protected String identifier; protected String label; protected int maxCardinality; protected int minCardinality; protected String namespace; protected int order; protected boolean required; protected String valueType; protected Map identifiers; protected boolean isEditable; // delimiter used to separate Field identifiers public final static String DELIMITER = ","; /** * @param field */ public BasicField(Field other) { this.identifier = other.getIdentifier(); this.valueType = other.getValueType(); this.required = other.isRequired(); this.minCardinality = other.getMinCardinality(); this.maxCardinality = other.getMaxCardinality(); this.namespace = other.getNamespaceAbbreviation(); this.description = other.getDescription(); this.identifiers = new Hashtable(); this.isEditable = other.isEditable(); if (other instanceof BasicField) { this.order = ((BasicField) other).getOrder(); Iterator it = ((BasicField) other).identifiers.keySet().iterator(); while (it.hasNext()) { String format = (String) it.next(); this.identifiers.put(format, ((BasicField) other).identifiers.get(format)); } } } public BasicField(String identifier, String valueType, boolean isEditable, boolean required, int minCardinality, int maxCardinality) { this.identifier = identifier; this.valueType = valueType; this.required = required; this.minCardinality = minCardinality; this.maxCardinality = maxCardinality; this.namespace = ""; this.label = ""; this.description = ""; this.order = 0; this.identifiers = new Hashtable(); this.isEditable = true; } public Object getDefaultValue() { return defaultValue; } public String getDescription() { return this.description; } public String getIdentifier() { return identifier; } public String getIdentifier(String format) { String tempString = null; String[] tokens = null; tempString = (String) this.identifiers.get(format); if (tempString == null) tempString = ""; tempString = tempString.trim(); // Is this a compound/delimited value? if (tempString.indexOf(DELIMITER) != -1) { // split the string based on the delimiter tokens = tempString.split(DELIMITER); // use the first delimiter as the identifier tempString = tokens[0]; } // end getIdentifier return tempString; } public String[] getIdentifierComplex(String format) { String tempString = null; String[] tokens = null; tempString = (String) this.identifiers.get(format); if (tempString == null) tempString = ""; tempString = tempString.trim(); // Is this a compound/delimited value? if (tempString.indexOf(DELIMITER) != -1) { // split the string based on the delimiter tokens = tempString.split(DELIMITER); } else // it's a simple value { tokens = new String[1]; tokens[0] = tempString; } return tokens; } // end getComplexIdentifers public String getLabel() { return this.label; } public int getMaxCardinality() { return maxCardinality; } public int getMinCardinality() { return minCardinality; } public String getNamespaceAbbreviation() { return this.namespace; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Schema.Field#getOrder() */ public int getOrder() { return order; } public String getValueType() { return valueType; } public boolean isEditable() { return isEditable; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Schema.Field#isMultivalued() */ public boolean isMultivalued() { return this.maxCardinality > 1; } public boolean isRequired() { return required; } public void setDefaultValue(Object value) { this.defaultValue = value; } /** * @param label */ public void setDescription(String description) { this.description = description; } public void setEditable(boolean isEditable) { this.isEditable = isEditable; } public void setIdentifier(String format, String identifier) { this.identifiers.put(format, identifier); } /** * @param label */ public void setLabel(String label) { this.label = label; } /** * @param maxCardinality * The maxCardinality to set. */ public void setMaxCardinality(int maxCardinality) { this.maxCardinality = maxCardinality; } /** * @param minCardinality * The minCardinality to set. */ public void setMinCardinality(int minCardinality) { this.minCardinality = minCardinality; } public void setNamespaceAbbreviation(String namespace) { this.namespace = namespace; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Schema.Field#setOrder(int) */ public void setOrder(int order) { this.order = order; } /** * @param required * The required to set. */ public void setRequired(boolean required) { this.required = required; } /** * @param valueType * The valueType to set. */ public void setValueType(String valueType) { this.valueType = valueType; } public String toString() { return "BasicField: " + this.identifier; } } /** * */ protected class BasicSchema implements Schema { protected String defaultNamespace; protected List fields; protected String identifier; protected Map index; protected Map namespaces; protected Map identifiers; /** * */ public BasicSchema() { this.fields = new Vector(); this.index = new Hashtable(); this.identifiers = new Hashtable(); } /** * @param schema */ public BasicSchema(Schema other) { this.identifier = other.getIdentifier(); this.defaultNamespace = other.getNamespaceAbbrev(); namespaces = new Hashtable(); List nsAbbrevs = other.getNamespaceAbbreviations(); if (nsAbbrevs != null) { Iterator nsIt = nsAbbrevs.iterator(); while (nsIt.hasNext()) { String nsAbbrev = (String) nsIt.next(); String ns = other.getNamespaceUri(nsAbbrev); namespaces.put(nsAbbrev, ns); } } this.identifiers = new Hashtable(); if (other instanceof BasicSchema) { Iterator it = ((BasicSchema) other).identifiers.keySet().iterator(); while (it.hasNext()) { String format = (String) it.next(); this.identifiers.put(format, ((BasicSchema) other).identifiers.get(format)); } } this.fields = new Vector(); this.index = new Hashtable(); List fields = other.getFields(); Iterator fieldIt = fields.iterator(); while (fieldIt.hasNext()) { Field field = (Field) fieldIt.next(); this.fields.add(new BasicField(field)); index.put(field.getIdentifier(), field); } } /** * @param schemaId */ public BasicSchema(String schemaId) { this.identifier = schemaId; this.fields = new Vector(); this.index = new Hashtable(); this.identifiers = new Hashtable(); } public void addAlternativeIdentifier(String fieldId, String altFormat, String altIdentifier) { BasicField field = (BasicField) this.index.get(fieldId); if (field != null) { field.setIdentifier(altFormat, altIdentifier); } } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Schema#addField(org.sakaiproject.citation.api.Schema.Field) */ public void addField(Field field) { this.index.put(field.getIdentifier(), field); this.fields.add(field); } /** * @param order * @param field */ public void addField(int order, Field field) { fields.add(order, field); index.put(identifier, field); } public BasicField addField(String identifier, String valueType, boolean isEditable, boolean required, int minCardinality, int maxCardinality) { if (fields == null) { fields = new Vector(); } if (index == null) { index = new Hashtable(); } BasicField field = new BasicField(identifier, valueType, isEditable, required, minCardinality, maxCardinality); fields.add(field); index.put(identifier, field); return field; } public BasicField addOptionalField(String identifier, String valueType, int minCardinality, int maxCardinality) { return addField(identifier, valueType, true, false, minCardinality, maxCardinality); } public BasicField addRequiredField(String identifier, String valueType, int minCardinality, int maxCardinality) { return addField(identifier, valueType, true, true, minCardinality, maxCardinality); } public Field getField(int index) { if (fields == null) { fields = new Vector(); } return (Field) fields.get(index); } public Field getField(String name) { if (index == null) { index = new Hashtable(); } return (Field) index.get(name); } public List getFields() { if (fields == null) { fields = new Vector(); } return fields; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Schema#getIdentifier() */ public String getIdentifier() { return this.identifier; } public String getIdentifier(String format) { return (String) this.identifiers.get(format); } public String getNamespaceAbbrev() { return defaultNamespace; } public List getNamespaceAbbreviations() { if (namespaces == null) { namespaces = new Hashtable(); } Collection keys = namespaces.keySet(); List rv = new Vector(); if (keys != null) { rv.addAll(keys); } return rv; } public String getNamespaceUri(String abbrev) { if (namespaces == null) { namespaces = new Hashtable(); } return (String) namespaces.get(abbrev); } public List getRequiredFields() { if (fields == null) { fields = new Vector(); } List required = new Vector(); Iterator it = fields.iterator(); while (it.hasNext()) { Field field = (Field) it.next(); if (field.isRequired()) { required.add(field); } } return required; } /** * @param identifier */ public void setIdentifier(String identifier) { this.identifier = identifier; } public void setIdentifier(String format, String identifier) { this.identifiers.put(format, identifier); } /** * */ public void sortFields() { Collections.sort(fields, new Comparator() { public int compare(Object arg0, Object arg1) { if (arg0 instanceof BasicField && arg1 instanceof BasicField) { Integer int0 = new Integer(((BasicField) arg0).getOrder()); Integer int1 = new Integer(((BasicField) arg1).getOrder()); return int0.compareTo(int1); } else if (arg0 instanceof Field && arg1 instanceof Field) { String lbl0 = ((Field) arg0).getLabel(); String lbl1 = ((Field) arg1).getLabel(); return lbl0.compareTo(lbl1); } else { throw new ClassCastException(arg0.toString() + " " + arg1.toString()); } } }); } public String toString() { return "BasicSchema: " + this.identifier; } } /** * */ protected interface Storage { /** * @param mediatype * @return */ public Citation addCitation(String mediatype); public CitationCollection addCollection(Map attributes, List citations); public Schema addSchema(Schema schema); public boolean checkCitation(String citationId); public boolean checkCollection(String collectionId); public boolean checkSchema(String schemaId); public long mostRecentUpdate(String collectionId); /** * Close. */ public void close(); public CitationCollection copyAll(String collectionId); public Citation getCitation(String citationId); public CitationCollection getCollection(String collectionId); public Schema getSchema(String schemaId); public List getSchemas(); /** * @return */ public List listSchemas(); /** * Open and be ready to read / write. */ public void open(); public void putSchemas(Collection schemas); public void removeCitation(Citation edit); public void removeCollection(CitationCollection edit); public void removeSchema(Schema schema); public void saveCitation(Citation edit); public void saveCollection(CitationCollection collection); public void updateSchema(Schema schema); public void updateSchemas(Collection schemas); } // interface Storage /** * */ public class UrlWrapper { protected String m_label; protected String m_url; protected boolean m_addPrefix; /** * @param label Link label * @param url URL * @param addPrefix Add the configured prefix text? */ public UrlWrapper(String label, String url, boolean addPrefix) { m_label = label; m_url = url; m_addPrefix = addPrefix; } /** * @param label Link label * @param url URL */ public UrlWrapper(String label, String url) { m_label = label; m_url = url; m_addPrefix = false; } /** * @return the label */ public String getLabel() { return m_label; } /** * @return the url */ public String getUrl() { return m_url; } /** * @return the "add prefix" setting */ public boolean addPrefix() { return m_addPrefix; } /** * @param label * the label to set */ public void setLabel(String label) { m_label = label; } /** * @param url * the url to set */ public void setUrl(String url) { m_url = url; } /** * @param addPrefix * the "add prefix" setting */ public void setAddPrefix(boolean addPrefix) { m_addPrefix = addPrefix; } } public static ResourceLoader rb; /** Our logger. */ private static Log M_log = LogFactory.getLog(BaseCitationService.class); protected static final String PROPERTY_DEFAULTVALUE = "sakai:defaultValue"; protected static final String PROPERTY_DESCRIPTION = "sakai:description"; protected static final String PROPERTY_HAS_ABBREVIATION = "sakai:hasAbbreviation"; protected static final String PROPERTY_HAS_CITATION = "sakai:hasCitation"; protected static final String PROPERTY_HAS_FIELD = "sakai:hasField"; protected static final String PROPERTY_HAS_NAMESPACE = "sakai:hasNamespace"; protected static final String PROPERTY_HAS_ORDER = "sakai:hasOrder"; protected static final String PROPERTY_HAS_SCHEMA = "sakai:hasSchema"; protected static final String PROPERTY_LABEL = "sakai:label"; protected static final String PROPERTY_MAXCARDINALITY = "sakai:maxCardinality"; protected static final String PROPERTY_MINCARDINALITY = "sakai:minCardinality"; protected static final String PROPERTY_NAMESPACE = "sakai:namespace"; protected static final String PROPERTY_REQUIRED = "sakai:required"; protected static final String PROPERTY_VALUETYPE = "sakai:valueType"; public static final String SCHEMA_PREFIX = "schema."; protected static AtomicInteger m_nextSerialNumber; /* * RIS MAPPINGS below */ protected static final String RIS_DELIM = " - "; /** * Set up a mapping of our type to RIS 'TY - ' values */ protected static final Map m_RISType = new Hashtable(); protected static final Map m_RISTypeInverse = new Hashtable(); /** * Which fields map onto the RIS Notes field? Include a prefix for the data, * if necessary. */ protected static final Map m_RISNoteFields = new Hashtable(); /** * Which fields need special processing for RIS export? */ protected static final Set m_RISSpecialFields = new java.util.HashSet(); static { m_RISType.put("unknown", "JOUR"); // Default to journal article m_RISType.put("article", "JOUR"); m_RISType.put("book", "BOOK"); m_RISType.put("chapter", "CHAP"); m_RISType.put("report", "RPRT"); m_RISType.put("proceed", "CONF"); m_RISType.put("electronic", "ELEC"); m_RISType.put("thesis", "THES"); m_RISTypeInverse.put("BOOK", "book"); m_RISTypeInverse.put("CHAP", "chapter"); m_RISTypeInverse.put("JOUR", "article"); m_RISTypeInverse.put("RPRT", "report"); m_RISTypeInverse.put("CONF", "proceed"); m_RISTypeInverse.put("ELEC", "electronic"); m_RISTypeInverse.put("THES", "thesis"); } static { m_RISNoteFields.put("language", "Language: "); m_RISNoteFields.put("doi", "DOI: "); m_RISNoteFields.put("rights", "Rights: "); } static { m_RISSpecialFields.add("date"); m_RISSpecialFields.add("doi"); } public static String escapeFieldName(String original) { if (original == null) { return ""; } original = original.trim(); try { // convert the string to bytes in UTF-8 byte[] bytes = original.getBytes("UTF-8"); StringBuilder buf = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { byte b = bytes[i]; // escape ascii control characters, ascii high bits, specials if (Schema.ESCAPE_FIELD_NAME.indexOf((char) b) != -1) { buf.append(Schema.ESCAPE_CHAR); // special funky way to // encode bad URL characters // - ParameterParser will // decode it } else { buf.append((char) b); } } String rv = buf.toString(); return rv; } catch (Exception e) { M_log.warn("BaseCitationService.escapeFieldName: ", e); return original; } } /** Dependency: CitationsConfigurationService. */ protected ConfigurationService m_configService = null; /** Dependency: ServerConfigurationService. */ protected ServerConfigurationService m_serverConfigurationService = null; /** * Dependency: ContentHostingService. * This is used for permission checking and the entity methods. */ protected ContentHostingService m_contentHostingService = null; /** Dependency: EntityManager. */ protected EntityManager m_entityManager = null; /** Depenedency: IdManager */ protected IdManager m_idManager = null; /** Dependency: OpenURLServiceImpl */ protected OpenURLServiceImpl m_openURLService; protected String m_defaultSchema; /** A Storage object for persistent storage. */ protected Storage m_storage = null; protected String m_relativeAccessPoint; /** * Dependency: the ResourceTypeRegistry */ protected ResourceTypeRegistry m_resourceTypeRegistry; /** * Dependency: inject the ResourceTypeRegistry * @param registry */ public void setResourceTypeRegistry(ResourceTypeRegistry registry) { m_resourceTypeRegistry = registry; } public void setOpenURLService(OpenURLServiceImpl openURLServiceImpl) { m_openURLService = openURLServiceImpl; } /** * @return the ResourceTypeRegistry */ public ResourceTypeRegistry getResourceTypeRegistry() { return m_resourceTypeRegistry; } public static final String PROP_TEMPORARY_CITATION_LIST = "citations.temporary_citation_list"; /** * Checks permissions to add a CitationList. Returns true if the user * has permission to add a resource in the collection identified by the * parameter. * @param contentCollectionId * @return */ public boolean allowAddCitationList(String contentCollectionId) { return m_contentHostingService.allowAddResource(contentCollectionId + "testing"); } /** * Checks permission to revise a CitationList, including permissions * to add, remove or revise citations within the CitationList. Returns * true if the user has permission to revise the resource identified by * the parameter. Also returns true if all of these conditions are met: * (1) the user is the creator of the specified resource, (2) the specified * resource is a temporary CitationList (as identified by the value of * the PROP_TEMPORARY_CITATION_LIST property), and (3) the user has * permission to add resources in the collection containing the * resource. * @param contentResourceId * @return */ public boolean allowReviseCitationList(String contentResourceId) { boolean allowed = m_contentHostingService.allowUpdateResource(contentResourceId); if(!allowed) { try { ResourceProperties props = m_contentHostingService.getProperties(contentResourceId); String temp_res = props.getProperty(CitationService.PROP_TEMPORARY_CITATION_LIST); String creator = props.getProperty(ResourceProperties.PROP_CREATOR); String contentCollectionId = m_contentHostingService.getContainingCollectionId(contentResourceId); SessionManager sessionManager = (SessionManager) ComponentManager.get("org.sakaiproject.tool.api.SessionManager"); String currentUser = sessionManager.getCurrentSessionUserId(); allowed = this.allowAddCitationList(contentCollectionId) && (temp_res != null) && currentUser.equals(creator); } catch(PermissionException e) { // do nothing: return false } catch (IdUnusedException e) { // do nothing: return false } } return allowed; } /** * * @return */ public boolean allowRemoveCitationList(String contentResourceId) { boolean allowed = m_contentHostingService.allowUpdateResource(contentResourceId); if(!allowed) { try { ResourceProperties props = m_contentHostingService.getProperties(contentResourceId); String temp_res = props.getProperty(CitationService.PROP_TEMPORARY_CITATION_LIST); String creator = props.getProperty(ResourceProperties.PROP_CREATOR); String contentCollectionId = m_contentHostingService.getContainingCollectionId(contentResourceId); SessionManager sessionManager = (SessionManager) ComponentManager.get("org.sakaiproject.tool.api.SessionManager"); String currentUser = sessionManager.getCurrentSessionUserId(); allowed = this.allowAddCitationList(contentCollectionId) && (temp_res != null) && currentUser.equals(creator); } catch(PermissionException e) { // do nothing: return false } catch (IdUnusedException e) { // do nothing: return false } } return allowed; } public Citation addCitation(String mediatype) { // work around to map google scholar's schemas with our's if (mediatype != null && mediatype.equalsIgnoreCase("proceeding")) { mediatype = "proceed"; } Citation edit = m_storage.addCitation(mediatype); return edit; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationService#addCollection() */ public CitationCollection addCollection() { CitationCollection edit = m_storage.addCollection(null, null); return edit; } /* * (non-Javadoc) * * @see org.sakaiproject.entity.api.EntityProducer#archive(java.lang.String, * org.w3c.dom.Document, java.util.Stack, java.lang.String, * java.util.List) */ public String archive(String siteId, Document doc, Stack stack, String archivePath, List attachments) { // TODO Auto-generated method stub return null; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationService#copyAll(java.lang.String) */ public CitationCollection copyAll(String collectionId) { return m_storage.copyAll(collectionId); } /** * Returns to uninitialized state. */ public void destroy() { if(m_storage != null) { m_storage.close(); m_storage = null; } } /** * Access the partial URL that forms the root of calendar URLs. * * @param relative * if true, form within the access path only (i.e. starting with * /content) * @return the partial URL that forms the root of calendar URLs. */ protected String getAccessPoint(boolean relative) { return (relative ? "" : m_serverConfigurationService.getAccessUrl()) + m_relativeAccessPoint; } // getAccessPoint /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationService#getCollection(java.lang.String) */ public CitationCollection getCollection(String collectionId) throws IdUnusedException { CitationCollection edit = m_storage.getCollection(collectionId); if (edit == null) { throw new IdUnusedException(collectionId); } return edit; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationService#getDefaultSchema() */ public Schema getDefaultSchema() { Schema rv = null; if (m_defaultSchema != null) { rv = m_storage.getSchema(m_defaultSchema); } return rv; } /* * (non-Javadoc) * * @see org.sakaiproject.entity.api.EntityProducer#getEntity(org.sakaiproject.entity.api.Reference) */ public Entity getEntity(Reference ref) { Entity entity = null; if (APPLICATION_ID.equals(ref.getType())) { if ( REF_TYPE_EXPORT_RIS_SEL.equals(ref.getSubType()) || REF_TYPE_EXPORT_RIS_ALL.equals(ref.getSubType()) ) { // these entities are citation collections String id = ref.getId(); if (id == null || id.trim().equals("")) { String reference = ref.getReference(); if (reference != null && reference.startsWith(REFERENCE_ROOT)) { id = reference.substring(REFERENCE_ROOT.length(), reference.length()); } } if (id != null && !id.trim().equals("")) { entity = m_storage.getCollection(id); } } else if (REF_TYPE_VIEW_LIST.equals(ref.getSubType())) { // these entities are actually in /content String id = ref.getId(); if (id == null || id.trim().equals("")) { String reference = ref.getReference(); if (reference.startsWith(REFERENCE_ROOT)) { reference = reference .substring(REFERENCE_ROOT.length(), reference.length()); } if (reference.startsWith(m_contentHostingService.REFERENCE_ROOT)) { id = reference.substring(m_contentHostingService.REFERENCE_ROOT.length(), reference.length()); } } if (id != null && !id.trim().equals("")) { try { entity = m_contentHostingService.getResource(id); } catch (PermissionException e) { M_log.warn("getEntity(" + id + ") ", e); } catch (IdUnusedException e) { M_log.warn("getEntity(" + id + ") ", e); } catch (TypeException e) { M_log.warn("getEntity(" + id + ") ", e); } } } } // and maybe others are in /citation return entity; } /* * (non-Javadoc) * * @see org.sakaiproject.entity.api.EntityProducer#getEntityAuthzGroups(org.sakaiproject.entity.api.Reference, * java.lang.String) */ public Collection getEntityAuthzGroups(Reference ref, String userId) { Collection azGroups = null; // entities that are actually in /content use the /content authz groups if(ref != null && ref.getReference() != null && ref.getReference().startsWith("/citation/content/")) { String altRef = ref.getReference().substring("/citation".length()); azGroups = m_contentHostingService.getEntityAuthzGroups(m_entityManager.newReference(altRef), userId); } return azGroups; } /* * (non-Javadoc) * * @see org.sakaiproject.entity.api.EntityProducer#getEntityDescription(org.sakaiproject.entity.api.Reference) */ public String getEntityDescription(Reference ref) { // TODO Auto-generated method stub return null; } /* * (non-Javadoc) * * @see org.sakaiproject.entity.api.EntityProducer#getEntityResourceProperties(org.sakaiproject.entity.api.Reference) */ public ResourceProperties getEntityResourceProperties(Reference ref) { // if it's a /content item, return its props // otherwise return null return null; } /* * (non-Javadoc) * * @see org.sakaiproject.entity.api.EntityProducer#getEntityUrl(org.sakaiproject.entity.api.Reference) */ public String getEntityUrl(Reference ref) { return null; } /* * (non-Javadoc) * * @see org.sakaiproject.entity.api.EntityProducer#getHttpAccess() */ public HttpAccess getHttpAccess() { // if it's a /content item, the access is via CitationListAccessServlet return new CitationListAccessServlet(); } /* * (non-Javadoc) * * @see org.sakaiproject.entity.api.EntityProducer#getLabel() */ public String getLabel() { // TODO Auto-generated method stub return null; } /** * @return */ public Set getMultivalued() { Set multivalued = new TreeSet(); Iterator schemaIt = m_storage.getSchemas().iterator(); while (schemaIt.hasNext()) { Schema schema = (Schema) schemaIt.next(); { Iterator fieldIt = schema.getFields().iterator(); while (fieldIt.hasNext()) { Field field = (Field) fieldIt.next(); if (field.getMaxCardinality() > 1) { multivalued.add(field.getIdentifier()); } } } } return multivalued; } /** * @return */ public Set getMultivalued(String type) { Set multivalued = new TreeSet(); Schema schema = m_storage.getSchema(type); { Iterator fieldIt = schema.getFields().iterator(); while (fieldIt.hasNext()) { Field field = (Field) fieldIt.next(); if (field.getMaxCardinality() > 1) { multivalued.add(field.getIdentifier()); } } } return multivalued; } public Schema getSchema(String name) { Schema schema = m_storage.getSchema(name); return schema; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationService#getSchemas() */ public List getSchemas() { List schemas = new Vector(m_storage.getSchemas()); return schemas; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.Schema#getSynonyms(java.lang.String) */ protected Set getSynonyms(String mediatype) { Set synonyms = new TreeSet(); if (mediatype.equalsIgnoreCase("article")) { synonyms.add("article"); synonyms.add("journal article"); synonyms.add("journal"); synonyms.add("periodical"); synonyms.add("newspaper article"); synonyms.add("magazine article"); synonyms.add("editorial"); synonyms.add("peer reviewed article"); synonyms.add("peer reviewed journal article"); synonyms.add("book review"); synonyms.add("review"); synonyms.add("meeting"); synonyms.add("wire feed"); synonyms.add("wire story"); synonyms.add("news"); synonyms.add("journal article (cije)"); } else if (mediatype.equalsIgnoreCase("book")) { synonyms.add("book"); synonyms.add("bk"); } else if (mediatype.equalsIgnoreCase("chapter")) { synonyms.add("chapter"); synonyms.add("book chapter"); synonyms.add("book section"); } else if (mediatype.equalsIgnoreCase("report")) { synonyms.add("report"); synonyms.add("editorial material"); synonyms.add("technical report"); synonyms.add("se"); synonyms.add("document (rie)"); } return synonyms; } public Citation getTemporaryCitation() { return new BasicCitation(); } public Citation getTemporaryCitation(Asset asset) { return new BasicCitation(asset); } public CitationCollection getTemporaryCollection() { return new BasicCitationCollection(true); } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationService#getValidPropertyNames() */ public Set getValidPropertyNames() { Set names = new TreeSet(); Iterator schemaIt = m_storage.getSchemas().iterator(); while (schemaIt.hasNext()) { Schema schema = (Schema) schemaIt.next(); { Iterator fieldIt = schema.getFields().iterator(); while (fieldIt.hasNext()) { Field field = (Field) fieldIt.next(); names.add(field.getIdentifier()); } } } return names; } // getValidPropertyNames public class CitationListCreateAction extends BaseInteractionAction { /** * @param id * @param actionType * @param typeId * @param helperId * @param requiredPropertyKeys */ public CitationListCreateAction(String id, ActionType actionType, String typeId, String helperId, List requiredPropertyKeys) { super(id, actionType, typeId, helperId, requiredPropertyKeys); } /* (non-Javadoc) * @see org.sakaiproject.content.util.BaseResourceAction#available(org.sakaiproject.content.api.ContentEntity) */ @Override public boolean available(ContentEntity entity) { return super.available(entity); } } /** * * */ public void init() { m_storage = newStorage(); m_nextSerialNumber = new AtomicInteger(0); m_relativeAccessPoint = CitationService.REFERENCE_ROOT; rb = new ResourceLoader("citations"); //initializeSchemas(); m_defaultSchema = "article"; // register as an entity producer m_entityManager.registerEntityProducer(this, REFERENCE_ROOT); if(m_configService.isCitationsEnabledByDefault() || m_configService.isAllowSiteBySiteOverride() ) { registerResourceType(); } } /** * */ protected void registerResourceType() { ResourceTypeRegistry registry = getResourceTypeRegistry(); List requiredPropertyKeys = new Vector(); requiredPropertyKeys.add(ContentHostingService.PROP_ALTERNATE_REFERENCE); requiredPropertyKeys.add(ResourceProperties.PROP_CONTENT_TYPE); BaseInteractionAction createAction = new CitationListCreateAction(ResourceToolAction.CREATE, ResourceToolAction.ActionType.CREATE_BY_HELPER, CitationService.CITATION_LIST_ID, CitationService.HELPER_ID, new Vector()); createAction.setLocalizer( new BaseResourceAction.Localizer() { public String getLabel() { return rb.getString("action.create"); } }); BaseInteractionAction reviseAction = new BaseInteractionAction(ResourceToolAction.REVISE_CONTENT, ResourceToolAction.ActionType.REVISE_CONTENT, CitationService.CITATION_LIST_ID, CitationService.HELPER_ID, new Vector()); reviseAction.setLocalizer( new BaseResourceAction.Localizer() { public String getLabel() { return rb.getString("action.revise"); } }); BaseServiceLevelAction moveAction = new BaseServiceLevelAction(ResourceToolAction.MOVE, ResourceToolAction.ActionType.MOVE, CitationService.CITATION_LIST_ID, true ); BaseServiceLevelAction revisePropsAction = new BaseServiceLevelAction(ResourceToolAction.REVISE_METADATA, ResourceToolAction.ActionType.REVISE_METADATA, CitationService.CITATION_LIST_ID, false ); BasicSiteSelectableResourceType typedef = new BasicSiteSelectableResourceType(CitationService.CITATION_LIST_ID); typedef.setSizeLabeler(new CitationSizeLabeler()); typedef.setLocalizer(new CitationLocalizer()); typedef.addAction(createAction); typedef.addAction(reviseAction); typedef.addAction(new CitationListDeleteAction()); typedef.addAction(new CitationListCopyAction()); typedef.addAction(new CitationListDuplicateAction()); typedef.addAction(revisePropsAction); typedef.addAction(moveAction); typedef.setEnabledByDefault(m_configService.isCitationsEnabledByDefault()); typedef.setIconLocation("sakai/citationlist.gif"); typedef.setHasRightsDialog(false); registry.register(typedef); } /** * */ protected void initializeSchemas() { BasicSchema unknown = new BasicSchema(); unknown.setIdentifier(CitationService.UNKNOWN_TYPE); BasicSchema article = new BasicSchema(); article.setIdentifier("article"); BasicSchema book = new BasicSchema(); book.setIdentifier("book"); BasicSchema chapter = new BasicSchema(); chapter.setIdentifier("chapter"); BasicSchema report = new BasicSchema(); report.setIdentifier("report"); /* schema ordering is different for different types */ /* * UNKNOWN (GENERIC) */ unknown.addField(Schema.CREATOR, Schema.SHORTTEXT, true, false, 0, Schema.UNLIMITED); unknown.addAlternativeIdentifier(Schema.CREATOR, RIS_FORMAT, "A1"); unknown.addField(Schema.TITLE, Schema.SHORTTEXT, true, true, 1, 1); unknown.addAlternativeIdentifier(Schema.TITLE, RIS_FORMAT, "T1"); unknown.addField(Schema.YEAR, Schema.NUMBER, true, false, 0, 1); // SAK-16740 -- rislabel for "year" is "Y1" (or "PY") unknown.addAlternativeIdentifier(Schema.YEAR, RIS_FORMAT, "Y1"); unknown.addField("date", Schema.NUMBER, true, false, 0, 1); unknown.addAlternativeIdentifier("date", RIS_FORMAT, "Y1"); unknown.addField(Schema.PUBLISHER, Schema.SHORTTEXT, true, false, 0, 1); unknown.addAlternativeIdentifier(Schema.PUBLISHER, RIS_FORMAT, "PB"); unknown.addField("publicationLocation", Schema.SHORTTEXT, true, false, 0, 1); unknown.addAlternativeIdentifier("publicationLocation", RIS_FORMAT, "CY"); unknown.addField(Schema.VOLUME, Schema.NUMBER, true, false, 0, 1); unknown.addAlternativeIdentifier(Schema.VOLUME, RIS_FORMAT, "VL"); unknown.addField(Schema.ISSUE, Schema.NUMBER, true, false, 0, 1); unknown.addAlternativeIdentifier(Schema.ISSUE, RIS_FORMAT, "IS"); unknown.addField(Schema.PAGES, Schema.NUMBER, true, false, 0, 1); unknown.addAlternativeIdentifier(Schema.PAGES, RIS_FORMAT, "SP"); unknown.addField("startPage", Schema.NUMBER, true, false, 0, 1); unknown.addAlternativeIdentifier("startPage", RIS_FORMAT, "SP"); unknown.addField("endPage", Schema.NUMBER, true, false, 0, 1); unknown.addAlternativeIdentifier("endPage", RIS_FORMAT, "EP"); unknown.addField("edition", Schema.NUMBER, true, false, 0, 1); unknown.addAlternativeIdentifier("edition", RIS_FORMAT, "VL"); unknown.addField("editor", Schema.SHORTTEXT, true, false, 0, Schema.UNLIMITED); unknown.addAlternativeIdentifier("editor", RIS_FORMAT, "A3"); unknown.addField(Schema.SOURCE_TITLE, Schema.SHORTTEXT, true, false, 0, 1); unknown.addAlternativeIdentifier(Schema.SOURCE_TITLE, RIS_FORMAT, "T3"); unknown.addField("Language", Schema.NUMBER, true, false, 0, 1); unknown.addField("abstract", Schema.LONGTEXT, true, false, 0, 1); unknown.addAlternativeIdentifier("abstract", RIS_FORMAT, "N2"); unknown.addField("note", Schema.LONGTEXT, true, false, 0, Schema.UNLIMITED); unknown.addAlternativeIdentifier("note", RIS_FORMAT, "N1"); unknown.addField(Schema.ISN, Schema.SHORTTEXT, true, false, 0, 1); unknown.addAlternativeIdentifier(Schema.ISN, RIS_FORMAT, "SN"); unknown.addField("subject", Schema.SHORTTEXT, true, false, 0, Schema.UNLIMITED); unknown.addAlternativeIdentifier("subject", RIS_FORMAT, "KW"); unknown.addField("locIdentifier", Schema.SHORTTEXT, true, false, 0, 1); unknown.addAlternativeIdentifier("locIdentifier", RIS_FORMAT, "M1"); unknown.addField("dateRetrieved", Schema.DATE, false, false, 0, 1); unknown.addField("openURL", Schema.SHORTTEXT, false, false, 0, 1); unknown.addField("doi", Schema.NUMBER, true, false, 0, 1); unknown.addField("rights", Schema.SHORTTEXT, true, false, 0, Schema.UNLIMITED); /* * ARTICLE */ article.addField(Schema.CREATOR, Schema.SHORTTEXT, true, false, 0, Schema.UNLIMITED); article.addAlternativeIdentifier(Schema.CREATOR, RIS_FORMAT, "A1"); article.addField(Schema.TITLE, Schema.SHORTTEXT, true, true, 1, 1); article.addAlternativeIdentifier(Schema.TITLE, RIS_FORMAT, "T1"); article.addField(Schema.SOURCE_TITLE, Schema.SHORTTEXT, true, false, 0, 1); article.addAlternativeIdentifier(Schema.SOURCE_TITLE, RIS_FORMAT, "JF"); article.addField(Schema.YEAR, Schema.NUMBER, true, false, 0, 1); // SAK-16740 -- rislabel for "year" is "Y1" (or "PY") article.addAlternativeIdentifier(Schema.YEAR, RIS_FORMAT, "Y1"); article.addField("date", Schema.NUMBER, true, false, 0, 1); article.addAlternativeIdentifier("date", RIS_FORMAT, "Y1"); article.addField(Schema.VOLUME, Schema.NUMBER, true, false, 0, 1); article.addAlternativeIdentifier(Schema.VOLUME, RIS_FORMAT, "VL"); article.addField(Schema.ISSUE, Schema.NUMBER, true, false, 0, 1); article.addAlternativeIdentifier(Schema.ISSUE, RIS_FORMAT, "IS"); article.addField(Schema.PAGES, Schema.NUMBER, true, false, 0, 1); article.addAlternativeIdentifier(Schema.PAGES, RIS_FORMAT, "SP"); article.addField("startPage", Schema.NUMBER, true, false, 0, 1); article.addAlternativeIdentifier("startPage", RIS_FORMAT, "SP"); article.addField("endPage", Schema.NUMBER, true, false, 0, 1); article.addAlternativeIdentifier("endPage", RIS_FORMAT, "EP"); article.addField("abstract", Schema.LONGTEXT, true, false, 0, 1); article.addAlternativeIdentifier("abstract", RIS_FORMAT, "N2"); article.addField("note", Schema.LONGTEXT, true, false, 0, Schema.UNLIMITED); article.addAlternativeIdentifier("note", RIS_FORMAT, "N1"); article.addField(Schema.ISN, Schema.SHORTTEXT, true, false, 0, 1); article.addAlternativeIdentifier(Schema.ISN, RIS_FORMAT, "SN"); article.addField("subject", Schema.SHORTTEXT, true, false, 0, Schema.UNLIMITED); article.addAlternativeIdentifier("subject", RIS_FORMAT, "KW"); article.addField("Language", Schema.NUMBER, true, false, 0, 1); article.addField("locIdentifier", Schema.SHORTTEXT, true, false, 0, 1); article.addAlternativeIdentifier("locIdentifier", RIS_FORMAT, "M1"); article.addField("dateRetrieved", Schema.DATE, false, false, 0, 1); article.addField("openURL", Schema.SHORTTEXT, false, false, 0, 1); article.addField("doi", Schema.NUMBER, true, false, 0, 1); article.addField("rights", Schema.SHORTTEXT, true, false, 0, Schema.UNLIMITED); /* * BOOK */ book.addField(Schema.CREATOR, Schema.SHORTTEXT, true, true, 1, Schema.UNLIMITED); book.addAlternativeIdentifier(Schema.CREATOR, RIS_FORMAT, "A1"); book.addField(Schema.TITLE, Schema.SHORTTEXT, true, true, 1, 1); book.addAlternativeIdentifier(Schema.TITLE, RIS_FORMAT, "BT"); book.addField(Schema.YEAR, Schema.NUMBER, true, false, 0, 1); // SAK-16740 -- rislabel for "year" is "Y1" (or "PY") book.addAlternativeIdentifier(Schema.YEAR, RIS_FORMAT, "Y1"); book.addField("date", Schema.NUMBER, true, false, 0, 1); book.addAlternativeIdentifier("date", RIS_FORMAT, "Y1"); book.addField(Schema.PUBLISHER, Schema.SHORTTEXT, true, false, 0, 1); book.addAlternativeIdentifier(Schema.PUBLISHER, RIS_FORMAT, "PB"); book.addField("publicationLocation", Schema.SHORTTEXT, true, false, 0, 1); book.addAlternativeIdentifier("publicationLocation", RIS_FORMAT, "CY"); book.addField("edition", Schema.NUMBER, true, false, 0, 1); book.addAlternativeIdentifier("edition", RIS_FORMAT, "VL"); book.addField("editor", Schema.SHORTTEXT, true, false, 0, Schema.UNLIMITED); book.addAlternativeIdentifier("editor", RIS_FORMAT, "A3"); book.addField(Schema.SOURCE_TITLE, Schema.SHORTTEXT, true, false, 0, 1); book.addAlternativeIdentifier(Schema.SOURCE_TITLE, RIS_FORMAT, "T3"); book.addField("abstract", Schema.LONGTEXT, true, false, 0, 1); book.addAlternativeIdentifier("abstract", RIS_FORMAT, "N2"); book.addField("note", Schema.LONGTEXT, true, false, 0, Schema.UNLIMITED); book.addAlternativeIdentifier("note", RIS_FORMAT, "N1"); book.addField(Schema.ISN, Schema.SHORTTEXT, true, false, 0, 1); book.addAlternativeIdentifier(Schema.ISN, RIS_FORMAT, "SN"); book.addField("subject", Schema.SHORTTEXT, true, false, 0, Schema.UNLIMITED); book.addAlternativeIdentifier("subject", RIS_FORMAT, "KW"); book.addField("Language", Schema.NUMBER, true, false, 0, 1); book.addField("locIdentifier", Schema.SHORTTEXT, true, false, 0, 1); book.addAlternativeIdentifier("locIdentifier", RIS_FORMAT, "M1"); book.addField("dateRetrieved", Schema.DATE, false, false, 0, 1); book.addField("openURL", Schema.SHORTTEXT, false, false, 0, 1); book.addField("doi", Schema.NUMBER, true, false, 0, 1); book.addField("rights", Schema.SHORTTEXT, true, false, 0, Schema.UNLIMITED); book.addAlternativeIdentifier(Schema.PAGES, RIS_FORMAT, "SP"); /* * CHAPTER */ chapter.addField(Schema.CREATOR, Schema.SHORTTEXT, true, true, 1, Schema.UNLIMITED); chapter.addAlternativeIdentifier(Schema.CREATOR, RIS_FORMAT, "A1"); chapter.addField(Schema.TITLE, Schema.SHORTTEXT, true, true, 1, 1); chapter.addAlternativeIdentifier(Schema.TITLE, RIS_FORMAT, "CT"); chapter.addField(Schema.YEAR, Schema.NUMBER, true, false, 0, 1); // SAK-16740 -- rislabel for "year" is "Y1" (or "PY") chapter.addAlternativeIdentifier(Schema.YEAR, RIS_FORMAT, "Y1"); chapter.addField("date", Schema.NUMBER, true, false, 0, 1); chapter.addAlternativeIdentifier("date", RIS_FORMAT, "Y1"); chapter.addField(Schema.PUBLISHER, Schema.SHORTTEXT, true, false, 0, 1); chapter.addAlternativeIdentifier(Schema.PUBLISHER, RIS_FORMAT, "PB"); chapter.addField("publicationLocation", Schema.SHORTTEXT, true, false, 0, 1); chapter.addAlternativeIdentifier("publicationLocation", RIS_FORMAT, "CY"); chapter.addField("edition", Schema.NUMBER, true, false, 0, 1); chapter.addAlternativeIdentifier("edition", RIS_FORMAT, "VL"); chapter.addField("editor", Schema.SHORTTEXT, true, false, 0, Schema.UNLIMITED); chapter.addAlternativeIdentifier("editor", RIS_FORMAT, "ED"); chapter.addField(Schema.SOURCE_TITLE, Schema.SHORTTEXT, true, false, 0, 1); chapter.addAlternativeIdentifier(Schema.SOURCE_TITLE, RIS_FORMAT, "BT"); chapter.addField(Schema.PAGES, Schema.NUMBER, true, false, 0, 1); chapter.addAlternativeIdentifier(Schema.PAGES, RIS_FORMAT, "SP"); chapter.addField("startPage", Schema.NUMBER, true, false, 0, 1); chapter.addAlternativeIdentifier("startPage", RIS_FORMAT, "SP"); chapter.addField("endPage", Schema.NUMBER, true, false, 0, 1); chapter.addAlternativeIdentifier("endPage", RIS_FORMAT, "EP"); chapter.addField("abstract", Schema.LONGTEXT, true, false, 0, 1); chapter.addAlternativeIdentifier("abstract", RIS_FORMAT, "N2"); chapter.addField("note", Schema.LONGTEXT, true, false, 0, Schema.UNLIMITED); chapter.addAlternativeIdentifier("note", RIS_FORMAT, "N1"); chapter.addField(Schema.ISN, Schema.SHORTTEXT, true, false, 0, 1); chapter.addAlternativeIdentifier(Schema.ISN, RIS_FORMAT, "SN"); chapter.addField("subject", Schema.SHORTTEXT, true, false, 0, Schema.UNLIMITED); chapter.addAlternativeIdentifier("subject", RIS_FORMAT, "KW"); chapter.addField("Language", Schema.NUMBER, true, false, 0, 1); chapter.addField("locIdentifier", Schema.SHORTTEXT, true, false, 0, 1); chapter.addAlternativeIdentifier("locIdentifier", RIS_FORMAT, "M1"); chapter.addField("dateRetrieved", Schema.DATE, false, false, 0, 1); chapter.addField("openURL", Schema.SHORTTEXT, false, false, 0, 1); chapter.addField("doi", Schema.NUMBER, true, false, 0, 1); chapter.addField("rights", Schema.SHORTTEXT, true, false, 0, Schema.UNLIMITED); /* * REPORT */ report.addField(Schema.CREATOR, Schema.SHORTTEXT, true, true, 1, Schema.UNLIMITED); report.addAlternativeIdentifier(Schema.CREATOR, RIS_FORMAT, "A1"); report.addField(Schema.TITLE, Schema.SHORTTEXT, true, true, 1, 1); report.addAlternativeIdentifier(Schema.TITLE, RIS_FORMAT, "T1"); report.addField(Schema.YEAR, Schema.NUMBER, true, false, 0, 1); // SAK-16740 -- rislabel for "year" is "Y1" (or "PY") report.addAlternativeIdentifier(Schema.YEAR, RIS_FORMAT, "Y1"); report.addField("date", Schema.NUMBER, true, false, 0, 1); report.addAlternativeIdentifier("date", RIS_FORMAT, "Y1"); report.addField(Schema.PUBLISHER, Schema.SHORTTEXT, true, false, 0, 1); report.addAlternativeIdentifier(Schema.PUBLISHER, RIS_FORMAT, "PB"); report.addField("publicationLocation", Schema.SHORTTEXT, true, false, 0, 1); report.addAlternativeIdentifier("publicationLocation", RIS_FORMAT, "CY"); report.addField("editor", Schema.SHORTTEXT, true, false, 0, Schema.UNLIMITED); report.addAlternativeIdentifier("editor", RIS_FORMAT, "A3"); report.addField("edition", Schema.NUMBER, true, false, 0, 1); report.addAlternativeIdentifier("edition", RIS_FORMAT, "VL"); report.addField(Schema.SOURCE_TITLE, Schema.SHORTTEXT, true, false, 0, 1); report.addAlternativeIdentifier(Schema.SOURCE_TITLE, RIS_FORMAT, "T3"); report.addField(Schema.PAGES, Schema.NUMBER, true, false, 0, 1); report.addAlternativeIdentifier(Schema.PAGES, RIS_FORMAT, "SP"); report.addField("abstract", Schema.LONGTEXT, true, false, 0, 1); report.addAlternativeIdentifier("abstract", RIS_FORMAT, "N2"); report.addField(Schema.ISN, Schema.SHORTTEXT, true, false, 0, 1); report.addAlternativeIdentifier(Schema.ISN, RIS_FORMAT, "SN"); report.addField("note", Schema.LONGTEXT, true, false, 0, Schema.UNLIMITED); report.addAlternativeIdentifier("note", RIS_FORMAT, "N1"); report.addField("subject", Schema.SHORTTEXT, true, false, 0, Schema.UNLIMITED); report.addAlternativeIdentifier("subject", RIS_FORMAT, "KW"); report.addField("Language", Schema.NUMBER, true, false, 0, 1); report.addField("locIdentifier", Schema.SHORTTEXT, true, false, 0, 1); report.addAlternativeIdentifier("locIdentifier", RIS_FORMAT, "M1"); report.addField("dateRetrieved", Schema.DATE, false, false, 0, 1); report.addField("openURL", Schema.SHORTTEXT, false, false, 0, 1); report.addField("doi", Schema.NUMBER, true, false, 0, 1); report.addField("rights", Schema.SHORTTEXT, true, false, 0, Schema.UNLIMITED); /* IGNORING 'Citation' field for now... unknown.addField("inlineCitation", Schema.SHORTTEXT, false, false, 0, Schema.UNLIMITED); article.addField("inlineCitation", Schema.SHORTTEXT, false, false, 0, Schema.UNLIMITED); book.addField("inlineCitation", Schema.SHORTTEXT, false, false, 0, Schema.UNLIMITED); chapter.addField("inlineCitation", Schema.SHORTTEXT, false, false, 0, Schema.UNLIMITED); report.addField("inlineCitation", Schema.SHORTTEXT, false, false, 0, Schema.UNLIMITED); */ if (m_storage.checkSchema(unknown.getIdentifier())) { m_storage.updateSchema(unknown); } else { m_storage.addSchema(unknown); } if (m_storage.checkSchema(article.getIdentifier())) { m_storage.updateSchema(article); } else { m_storage.addSchema(article); } if (m_storage.checkSchema(book.getIdentifier())) { m_storage.updateSchema(book); } else { m_storage.addSchema(book); } if (m_storage.checkSchema(chapter.getIdentifier())) { m_storage.updateSchema(chapter); } else { m_storage.addSchema(chapter); } if (m_storage.checkSchema(report.getIdentifier())) { m_storage.updateSchema(report); } else { m_storage.addSchema(report); } } public class CitationListDeleteAction extends BaseServiceLevelAction { public CitationListDeleteAction() { super(ResourceToolAction.DELETE, ResourceToolAction.ActionType.DELETE, CitationService.CITATION_LIST_ID, true); } public void finalizeAction(Reference reference) { try { ContentResource resource = (ContentResource) reference.getEntity(); String collectionId = new String(resource.getContent()); CitationCollection collection = getCollection(collectionId); removeCollection(collection); } catch(IdUnusedException e) { M_log.warn("IdUnusedException ", e); } catch(ServerOverloadException e) { M_log.warn("ServerOverloadException ", e); } } } public class CitationLocalizer implements BasicResourceType.Localizer { /** * * @return */ public String getLabel() { return rb.getString("list.title"); } /** * * @param member * @return */ public String getLocalizedHoverText(ContentEntity member) { return rb.getString("list.title"); } } public class CitationSizeLabeler implements BasicResourceType.SizeLabeler { public String getLongSizeLabel(ContentEntity entity) { return getSizeLabel(entity); } public String getSizeLabel(ContentEntity entity) { String label = null; if(entity instanceof ContentResource) { byte[] collectionId = null; ContentResource resource = (ContentResource) entity; try { collectionId = resource.getContent(); if(collectionId != null) { CitationCollection collection = getCollection(new String(collectionId)); String[] args = new String[]{ Integer.toString(collection.size())}; label = rb.getFormattedMessage("citation.count", args); } } catch(Exception e) { String citationCollectionId = "null"; if(collectionId != null) { citationCollectionId = collectionId.toString(); } M_log.warn("Unable to determine size of CitationCollection for entity: entityId == " + entity.getId() + " citationCollectionId == " + collectionId + " exception == " + e.toString()); } } return label; } } public class CitationListCopyAction extends BaseServiceLevelAction { public CitationListCopyAction() { super(ResourceToolAction.COPY, ResourceToolAction.ActionType.COPY, CitationService.CITATION_LIST_ID, true); } @Override public void finalizeAction(Reference reference) { copyCitationCollection(reference); } } public class CitationListDuplicateAction extends BaseServiceLevelAction { public CitationListDuplicateAction() { super(ResourceToolAction.DUPLICATE, ResourceToolAction.ActionType.DUPLICATE, CitationService.CITATION_LIST_ID, false); } @Override public void finalizeAction(Reference reference) { copyCitationCollection(reference); } } /** * @param schemaId * @param fieldId * @return */ public boolean isMultivalued(String schemaId, String fieldId) { Schema schema = getSchema(schemaId.toLowerCase()); if (schema == null) { if (getSynonyms("article").contains(schemaId.toLowerCase())) { schema = getSchema("article"); } else if (getSynonyms("book").contains(schemaId.toLowerCase())) { schema = getSchema("book"); } else if (getSynonyms("chapter").contains(schemaId.toLowerCase())) { schema = getSchema("chapter"); } else if (getSynonyms("report").contains(schemaId.toLowerCase())) { schema = getSchema("report"); } else { schema = this.getSchema("unknown"); } } Field field = schema.getField(fieldId); if (field == null) { return false; } return (field.isMultivalued()); } /** * Access a list of all schemas that have been defined (other than the * "unknown" type). * * @return A list of Strings representing the identifiers for known schemas. */ public List listSchemas() { Set names = (Set) m_storage.listSchemas(); return new Vector(names); } /* * (non-Javadoc) * * @see org.sakaiproject.entity.api.EntityProducer#merge(java.lang.String, * org.w3c.dom.Element, java.lang.String, java.lang.String, * java.util.Map, java.util.Map, java.util.Set) */ public String merge(String siteId, Element root, String archivePath, String fromSiteId, Map attachmentNames, Map userIdTrans, Set userListAllowImport) { // TODO Auto-generated method stub return null; } /** * Construct a Storage object. * * @return The new storage object. */ public abstract Storage newStorage(); /** * @return */ protected Integer nextSerialNumber() { return m_nextSerialNumber.getAndIncrement(); } /* * (non-Javadoc) * * @see org.sakaiproject.entity.api.EntityProducer#parseEntityReference(java.lang.String, * org.sakaiproject.entity.api.Reference) */ public boolean parseEntityReference(String reference, Reference ref) { boolean citationEntity = false; if (reference.startsWith(CitationService.REFERENCE_ROOT)) { citationEntity = true; String[] parts = StringUtils.split(reference, Entity.SEPARATOR); String subType = null; String context = null; String id = null; String container = null; // the first part will be citation, then next the service; two examples of arrays: // [citation, content, group, dbde854b-80f3-460f-b89e-340879538239, test123] // [citation, export_ris_all, b60b889d-79fe-454b-8283-e41a135ad62a] if (parts.length > 2) { subType = parts[1]; if (CitationService.REF_TYPE_EXPORT_RIS_ALL.equals(subType) || CitationService.REF_TYPE_EXPORT_RIS_SEL.equals(subType)) { context = parts[2]; id = parts[2]; ref.set(APPLICATION_ID, subType, id, container, context); } else if ("content".equals(subType)) { String wrappedRef = reference.substring(REFERENCE_ROOT.length(), reference .length()); Reference wrapped = m_entityManager.newReference(wrappedRef); if(ref == null) { M_log.warn("CitationService.parseEntityReference called with null Reference object", new Throwable()); } else { ref.set(APPLICATION_ID, REF_TYPE_VIEW_LIST, wrapped.getId(), wrapped .getContainer(), wrapped.getContext()); } } else { M_log.warn(".parseEntityReference(): unknown citation subtype: " + subType + " in ref: " + reference); citationEntity = false; } } else { citationEntity = false; } } return citationEntity; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationService#removeCollection(org.sakaiproject.citation.api.CitationCollection) */ public void removeCollection(CitationCollection edit) { // TODO Auto-generated method stub } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationService#save(org.sakaiproject.citation.api.Citation) */ public void save(Citation citation) { if (citation instanceof BasicCitation && ((BasicCitation) citation).isTemporary()) { ((BasicCitation) citation).m_id = m_idManager.createUuid(); ((BasicCitation) citation).m_temporary = false; ((BasicCitation) citation).m_serialNumber = null; } this.m_storage.saveCitation(citation); } public void setIdManager(IdManager idManager) { m_idManager = idManager; } /* * (non-Javadoc) * * @see org.sakaiproject.citation.api.CitationService#save(org.sakaiproject.citation.api.CitationCollection) */ public void save(CitationCollection collection) { this.m_storage.saveCollection(collection); } /** * Dependency: ConfigurationService. * * @param service * The ConfigurationService. */ public void setConfigurationService(ConfigurationService service) { m_configService = service; } /** * Dependency: ContentHostingService. * * @param service * The ContentHostingService. */ public void setContentHostingService(ContentHostingService service) { m_contentHostingService = service; } /** * Dependency: EntityManager. * * @param service * The EntityManager. */ public void setEntityManager(EntityManager service) { m_entityManager = service; } /** * Dependency: ServerConfigurationService. * * @param service * The ServerConfigurationService. */ public void setServerConfigurationService(ServerConfigurationService service) { m_serverConfigurationService = service; } /* * (non-Javadoc) * * @see org.sakaiproject.entity.api.EntityProducer#willArchiveMerge() */ public boolean willArchiveMerge() { // TODO Auto-generated method stub return false; } public final class Counter { private int value; private Integer lock = new Integer(0); public Counter() { value = 0; } public Counter(int val) { value = val; } public void increment() { synchronized(lock) { value++; } } public void decrement() { synchronized(lock) { value--; } } public int intValue() { return value; } } /** * @return the attemptToMatchSchema */ public boolean isAttemptToMatchSchema() { return attemptToMatchSchema; } /** * @param attemptToMatchSchema the attemptToMatchSchema to set */ public void setAttemptToMatchSchema(boolean attemptToMatchSchema) { this.attemptToMatchSchema = attemptToMatchSchema; } /** * @param reference */ private void copyCitationCollection(Reference reference) { ContentHostingService contentService = (ContentHostingService) ComponentManager.get(ContentHostingService.class); try { ContentResourceEdit edit = contentService.editResource(reference.getId()); String collectionId = new String(edit.getContent()); CitationCollection oldCollection = getCollection(collectionId); BasicCitationCollection newCollection = new BasicCitationCollection(); newCollection.copy((BasicCitationCollection) oldCollection); save(newCollection); edit.setContent(newCollection.getId().getBytes()); // When duplicating/copying a citations list notifications shouldn't be sent so that // this follow the behaviour of the standard resource types in Sakai. contentService.commitResource(edit, NotificationService.NOTI_NONE); } catch(IdUnusedException e) { M_log.warn("IdUnusedException ", e); } catch(ServerOverloadException e) { M_log.warn("ServerOverloadException ", e); } catch (PermissionException e) { M_log.warn("PermissionException ", e); } catch (TypeException e) { M_log.warn("TypeException ", e); } catch (InUseException e) { M_log.warn("InUseException ", e); } catch (OverQuotaException e) { M_log.warn("OverQuotaException ", e); } } public Citation addCitation(HttpServletRequest request) { ContextObject co = m_openURLService.parse(request); Citation citation = null; if (co != null) { citation = m_openURLService.convert(co); } return citation; } } // BaseCitationService