001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.fcrepo.kernel.api.utils;
019
020import org.apache.jena.datatypes.xsd.XSDDateTime;
021import org.apache.jena.rdf.model.Property;
022import org.apache.jena.rdf.model.RDFNode;
023import org.apache.jena.rdf.model.Statement;
024import org.fcrepo.kernel.api.exception.MalformedRdfException;
025
026import java.util.Calendar;
027
028import static org.fcrepo.kernel.api.RdfLexicon.CREATED_BY;
029import static org.fcrepo.kernel.api.RdfLexicon.CREATED_DATE;
030import static org.fcrepo.kernel.api.RdfLexicon.LAST_MODIFIED_BY;
031import static org.fcrepo.kernel.api.RdfLexicon.LAST_MODIFIED_DATE;
032
033/**
034 * Some server managed triples can have the prohibition on user-management overridden.  While
035 * the server still updates them implicitly, it may be possible in some cases for a user
036 * request to override them.
037 *
038 * @author Mike Durbin
039 */
040public class RelaxedPropertiesHelper {
041
042    /**
043     * Gets the created date (if any) that was included in the statements.
044     * @param statements statements to consider
045     * @return the date that should be set for the CREATED_DATE or null if it should be
046     *         untouched
047     */
048    public static Calendar getCreatedDate(final Iterable<Statement> statements) {
049        return extractSingleCalendarValue(statements, CREATED_DATE);
050    }
051
052    /**
053     * Gets the created by user (if any) that is included within the statements.
054     * @param statements statements to consider
055     * @return the date that should be set for the CREATED_BY or null if it should be
056     *         untouched
057     */
058    public static String getCreatedBy(final Iterable<Statement> statements) {
059        return extractSingleStringValue(statements, CREATED_BY);
060    }
061
062    /**
063     * Gets the modified date (if any) that was included within the statements.
064     * @param statements statements to consider
065     * @return the date that should be set for the LAST_MODIFIED_DATE or null if it should be
066     *         untouched
067     */
068    public static Calendar getModifiedDate(final Iterable<Statement> statements) {
069        return extractSingleCalendarValue(statements, LAST_MODIFIED_DATE);
070    }
071
072    /**
073     * Gets the modified by user (if any) that was included within the statements.
074     * @param statements statements to consider
075     * @return the date that should be set for the MODIFIED_BY or null if it should be
076     *         untouched
077     */
078    public static String getModifiedBy(final Iterable<Statement> statements) {
079       return extractSingleStringValue(statements, LAST_MODIFIED_BY);
080    }
081
082    private static String extractSingleStringValue(final Iterable<Statement> statements, final Property predicate) {
083        String username = null;
084        for (Statement added : statements) {
085            if (added.getPredicate().equals(predicate)) {
086                if (username == null) {
087                    username = added.getObject().asLiteral().getString();
088                } else {
089                    throw new MalformedRdfException(predicate + " may only appear once!");
090                }
091            }
092        }
093        return username;
094    }
095
096    private static Calendar extractSingleCalendarValue(final Iterable<Statement> statements,
097                                                       final Property predicate) {
098        Calendar cal = null;
099        for (Statement added : statements) {
100            if (added.getPredicate().equals(predicate)) {
101                if (cal == null) {
102                    cal = RelaxedPropertiesHelper.parseExpectedXsdDateTimeValue(added.getObject());
103                } else {
104                    throw new MalformedRdfException(predicate + " may only appear once!");
105                }
106            }
107        }
108        return cal;
109    }
110
111    /**
112     * Parses an RDFNode that is expected to be a literal of type xsd:dateTime into a Java Calendar
113     * object.
114     * @param node a node representing an xsd:dateTime literal
115     * @return a Calendar representation of the expressed dateTime
116     */
117    private static Calendar parseExpectedXsdDateTimeValue(final RDFNode node) {
118        final Object value = node.asLiteral().getValue();
119        if (value instanceof XSDDateTime) {
120            return ((XSDDateTime) value).asCalendar();
121        } else {
122            throw new IllegalArgumentException("Expected an xsd:dateTime!");
123        }
124    }
125
126    // Prevent instantiation
127    private RelaxedPropertiesHelper() {
128
129    }
130}