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.camel.processor;
019
020import static java.util.Arrays.stream;
021import static java.util.Collections.emptyList;
022import static java.util.stream.Collectors.toList;
023import static org.apache.camel.util.ExchangeHelper.getMandatoryHeader;
024import static org.apache.jena.util.URIref.encode;
025import static org.fcrepo.camel.FcrepoHeaders.FCREPO_BASE_URL;
026import static org.fcrepo.camel.FcrepoHeaders.FCREPO_IDENTIFIER;
027import static org.fcrepo.camel.FcrepoHeaders.FCREPO_URI;
028import static org.slf4j.LoggerFactory.getLogger;
029
030import java.util.List;
031
032import org.apache.camel.CamelContext;
033import org.apache.camel.Exchange;
034import org.apache.camel.NoSuchHeaderException;
035
036import org.slf4j.Logger;
037
038/**
039 * Utility functions for fcrepo processor classes
040 * @author Aaron Coburn
041 * @since November 14, 2014
042 */
043
044public final class ProcessorUtils {
045
046    private static final Logger LOGGER  = getLogger(ProcessorUtils.class);
047
048    /**
049     * This is a utility class; the constructor is off-limits.
050     */
051    private ProcessorUtils() {
052    }
053
054    private static String trimTrailingSlash(final String path) {
055        if (path.endsWith("/")) {
056            return path.substring(0, path.length() - 1);
057        }
058        return path;
059    }
060
061    /**
062     * Extract the subject URI from the incoming exchange.
063     * @param exchange the incoming Exchange
064     * @return the subject URI
065     * @throws NoSuchHeaderException when the CamelFcrepoBaseUrl header is not present
066     */
067    public static String getSubjectUri(final Exchange exchange) throws NoSuchHeaderException {
068        final String uri = exchange.getIn().getHeader(FCREPO_URI, "", String.class);
069        if (uri.isEmpty()) {
070            final String base = getMandatoryHeader(exchange, FCREPO_BASE_URL, String.class);
071            final String path = exchange.getIn().getHeader(FCREPO_IDENTIFIER, "", String.class);
072            return trimTrailingSlash(base) + path;
073        }
074        return uri;
075    }
076
077    /**
078     * Create a DELETE WHERE { ... } statement from the provided subject
079     *
080     * @param subject the subject of the triples to delete.
081     * @param namedGraph an optional named graph
082     * @return the delete statement
083     */
084    public static String deleteWhere(final String subject, final String namedGraph) {
085        final StringBuilder stmt = new StringBuilder("DELETE WHERE { ");
086
087        if (!namedGraph.isEmpty()) {
088            stmt.append("GRAPH ");
089            stmt.append("<" + encode(namedGraph) + ">");
090            stmt.append(" { ");
091        }
092
093        stmt.append("<" + encode(subject) + ">");
094        stmt.append(" ?p ?o ");
095
096        if (!namedGraph.isEmpty()) {
097            stmt.append("} ");
098        }
099
100        stmt.append("}");
101        return stmt.toString();
102    }
103
104    /**
105     *  Create an INSERT DATA { ... } update query with the provided ntriples
106     *
107     *  @param serializedGraph the triples to insert
108     *  @param namedGraph an optional named graph
109     *  @return the insert statement
110     */
111    public static String insertData(final String serializedGraph, final String namedGraph) {
112        final StringBuilder query = new StringBuilder("INSERT DATA { ");
113
114        if (!namedGraph.isEmpty()) {
115            query.append("GRAPH <");
116            query.append(encode(namedGraph));
117            query.append("> { ");
118        }
119
120        query.append(serializedGraph);
121
122        if (!namedGraph.isEmpty()) {
123            query.append("} ");
124        }
125
126        query.append("}");
127        return query.toString();
128    }
129
130    /**
131     * Tokenize a property placeholder value
132     *
133     * @param context the camel context
134     * @param property the name of the property placeholder
135     * @param token the token used for splitting the value
136     * @return a list of values
137     */
138    public static List<String> tokenizePropertyPlaceholder(final CamelContext context, final String property,
139            final String token) {
140        try {
141            return stream(context.resolvePropertyPlaceholders(property).split(token)).map(String::trim)
142                .filter(val -> !val.isEmpty()).collect(toList());
143        } catch (final Exception ex) {
144            LOGGER.debug("No property value found for {}", property);
145            return emptyList();
146        }
147    }
148}
149