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.http.api;
019
020import com.google.common.annotations.VisibleForTesting;
021import org.apache.jena.graph.Node;
022import org.apache.jena.rdf.model.Resource;
023import org.apache.commons.lang3.StringUtils;
024import org.fcrepo.http.commons.AbstractResource;
025import org.fcrepo.http.commons.api.rdf.HttpResourceConverter;
026import org.fcrepo.http.commons.session.HttpSession;
027import org.fcrepo.kernel.api.exception.SessionMissingException;
028import org.fcrepo.kernel.api.exception.TombstoneException;
029import org.fcrepo.kernel.api.identifiers.IdentifierConverter;
030import org.fcrepo.kernel.api.models.FedoraResource;
031import org.fcrepo.kernel.api.models.Tombstone;
032import org.slf4j.Logger;
033
034import java.net.URI;
035import java.security.Principal;
036import java.util.regex.Pattern;
037import javax.inject.Inject;
038import javax.ws.rs.core.Context;
039import javax.ws.rs.core.HttpHeaders;
040import javax.ws.rs.core.SecurityContext;
041import javax.ws.rs.core.UriInfo;
042
043import static org.fcrepo.kernel.api.observer.OptionalValues.BASE_URL;
044import static org.fcrepo.kernel.api.observer.OptionalValues.USER_AGENT;
045import static org.slf4j.LoggerFactory.getLogger;
046
047/**
048 * @author cabeer
049 * @since 10/5/14
050 */
051abstract public class FedoraBaseResource extends AbstractResource {
052
053    private static final Logger LOGGER = getLogger(FedoraBaseResource.class);
054
055    static final String JMS_BASEURL_PROP = "fcrepo.jms.baseUrl";
056
057    private static final Pattern TRAILING_SLASH_REGEX = Pattern.compile("/+$");
058
059    @Inject
060    protected HttpSession session;
061
062    @Context
063    protected SecurityContext securityContext;
064
065    protected IdentifierConverter<Resource, FedoraResource> idTranslator;
066
067    protected IdentifierConverter<Resource, FedoraResource> translator() {
068        if (idTranslator == null) {
069            idTranslator = new HttpResourceConverter(session(),
070                    uriInfo.getBaseUriBuilder().clone().path(FedoraLdp.class));
071        }
072
073        return idTranslator;
074    }
075
076    /**
077     * This is a helper method for using the idTranslator to convert this resource into an associated Jena Node.
078     *
079     * @param resource to be converted into a Jena Node
080     * @return the Jena node
081     */
082    protected Node asNode(final FedoraResource resource) {
083        return translator().reverse().convert(resource).asNode();
084    }
085
086    /**
087     * Get the FedoraResource for the resource at the external path
088     * @param externalPath the external path
089     * @return the fedora resource at the external path
090     */
091    @VisibleForTesting
092    public FedoraResource getResourceFromPath(final String externalPath) {
093        final Resource resource = translator().toDomain(externalPath);
094        final FedoraResource fedoraResource = translator().convert(resource);
095
096        if (fedoraResource instanceof Tombstone) {
097            final String resourceURI = TRAILING_SLASH_REGEX.matcher(resource.getURI()).replaceAll("");
098            throw new TombstoneException(fedoraResource, resourceURI + "/fcr:tombstone");
099        }
100
101        return fedoraResource;
102    }
103
104    /**
105     * Set the baseURL for JMS events.
106     * @param uriInfo the uri info
107     * @param headers HTTP headers
108     **/
109    protected void setUpJMSInfo(final UriInfo uriInfo, final HttpHeaders headers) {
110        try {
111            String baseURL = getBaseUrlProperty(uriInfo);
112            if (baseURL.length() == 0) {
113                baseURL = uriInfo.getBaseUri().toString();
114            }
115            LOGGER.debug("setting baseURL = " + baseURL);
116            session.getFedoraSession().addSessionData(BASE_URL, baseURL);
117            if (!StringUtils.isBlank(headers.getHeaderString("user-agent"))) {
118                session.getFedoraSession().addSessionData(USER_AGENT, headers.getHeaderString("user-agent"));
119            }
120        } catch (final Exception ex) {
121            LOGGER.warn("Error setting baseURL", ex.getMessage());
122        }
123    }
124
125    /**
126     * Produce a baseURL for JMS events using the system property fcrepo.jms.baseUrl of the form http[s]://host[:port],
127     * if it exists.
128     *
129     * @param uriInfo used to build the base url
130     * @return String the base Url
131     */
132    private String getBaseUrlProperty(final UriInfo uriInfo) {
133        final String propBaseURL = System.getProperty(JMS_BASEURL_PROP, "");
134        if (propBaseURL.length() > 0 && propBaseURL.startsWith("http")) {
135            final URI propBaseUri = URI.create(propBaseURL);
136            if (propBaseUri.getPort() < 0) {
137                return uriInfo.getBaseUriBuilder().port(-1).uri(propBaseUri).toString();
138            }
139            return uriInfo.getBaseUriBuilder().uri(propBaseUri).toString();
140        }
141        return "";
142    }
143
144    private HttpSession session() {
145        if (session == null) {
146            throw new SessionMissingException("Invalid session");
147        }
148        return session;
149    }
150
151    protected String getUserPrincipal() {
152        final Principal p = securityContext.getUserPrincipal();
153        return p == null ? null : p.getName();
154    }
155}