001/**
002 * Copyright 2015 DuraSpace, Inc.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.fcrepo.kernel.impl.rdf.impl;
017
018import static com.google.common.collect.ImmutableSet.builder;
019import static com.hp.hpl.jena.graph.NodeFactory.createLiteral;
020import static com.hp.hpl.jena.graph.NodeFactory.createURI;
021import static com.hp.hpl.jena.graph.Triple.create;
022import static com.hp.hpl.jena.rdf.model.ResourceFactory.createTypedLiteral;
023import static org.fcrepo.kernel.FedoraJcrTypes.ROOT;
024import static org.fcrepo.kernel.RdfLexicon.HAS_FIXITY_CHECK_COUNT;
025import static org.fcrepo.kernel.RdfLexicon.HAS_FIXITY_ERROR_COUNT;
026import static org.fcrepo.kernel.RdfLexicon.HAS_FIXITY_REPAIRED_COUNT;
027import static org.fcrepo.kernel.RdfLexicon.HAS_NODE_TYPE;
028import static org.fcrepo.kernel.RdfLexicon.REPOSITORY_NAMESPACE;
029import static org.slf4j.LoggerFactory.getLogger;
030
031import com.hp.hpl.jena.rdf.model.Resource;
032import org.apache.commons.lang.StringUtils;
033import org.fcrepo.kernel.models.FedoraResource;
034import org.fcrepo.kernel.identifiers.IdentifierConverter;
035import org.fcrepo.metrics.RegistryService;
036
037import java.util.Map;
038import java.util.SortedMap;
039
040import javax.jcr.Repository;
041import javax.jcr.RepositoryException;
042import javax.jcr.nodetype.NodeType;
043import javax.jcr.nodetype.NodeTypeIterator;
044import javax.jcr.nodetype.NodeTypeManager;
045
046import org.fcrepo.kernel.impl.services.functions.GetClusterConfiguration;
047import org.modeshape.jcr.JcrRepository;
048import org.slf4j.Logger;
049
050import com.codahale.metrics.Counter;
051import com.google.common.collect.ImmutableSet;
052import com.hp.hpl.jena.graph.Triple;
053
054/**
055 * Assemble {@link Triple}s derived from the root of a repository.
056 *
057 * @author ajs6f
058 * @since Oct 18, 2013
059 */
060public class RootRdfContext extends NodeRdfContext {
061
062    private static final Logger LOGGER = getLogger(RootRdfContext.class);
063    static final RegistryService registryService = RegistryService.getInstance();
064
065    /**
066     * Ordinary constructor.
067     *
068     * @param resource the resource
069     * @param idTranslator the id translator
070     * @throws RepositoryException if repository exception occurred
071     */
072    public RootRdfContext(final FedoraResource resource,
073                          final IdentifierConverter<Resource, FedoraResource> idTranslator)
074            throws RepositoryException {
075        super(resource, idTranslator);
076
077        if (resource().hasType(ROOT)) {
078            concatRepositoryTriples();
079        }
080    }
081
082    private void concatRepositoryTriples() throws RepositoryException {
083        LOGGER.trace("Creating RDF triples for repository description");
084        final Repository repository = resource().getNode().getSession().getRepository();
085
086        final ImmutableSet.Builder<Triple> b = builder();
087
088        for (final String key : repository.getDescriptorKeys()) {
089            final String descriptor = repository.getDescriptor(key);
090            if (descriptor != null) {
091                // Create a URI from the jcr.Repository constant values,
092                // converting them from dot notation (identifier.stability)
093                // to the camel case that is more common in RDF properties.
094                final StringBuilder uri = new StringBuilder(REPOSITORY_NAMESPACE);
095                uri.append("repository");
096                for (final String segment : key.split("\\.")) {
097                    uri.append(StringUtils.capitalize(segment));
098                }
099                b.add(create(subject(), createURI(uri.toString()),
100                        createLiteral(descriptor)));
101            }
102        }
103        final NodeTypeManager nodeTypeManager =
104            resource().getNode().getSession().getWorkspace().getNodeTypeManager();
105
106        final NodeTypeIterator nodeTypes = nodeTypeManager.getAllNodeTypes();
107        while (nodeTypes.hasNext()) {
108            final NodeType nodeType = nodeTypes.nextNodeType();
109            b.add(create(subject(), HAS_NODE_TYPE.asNode(),
110                    createLiteral(nodeType.getName())));
111        }
112
113        /*
114            FIXME: removing due to performance problems, esp. w/ many files on federated filesystem
115            see: https://www.pivotaltracker.com/story/show/78647248
116
117            b.add(create(subject(), HAS_OBJECT_COUNT.asNode(), createLiteral(String
118                    .valueOf(getRepositoryCount(repository)))));
119            b.add(create(subject(), HAS_OBJECT_SIZE.asNode(), createLiteral(String
120                    .valueOf(getRepositorySize(repository)))));
121        */
122
123        // Get the cluster configuration, if available
124        // this ugly test checks to see whether this is an ordinary JCR
125        // repository or a ModeShape repo, which will possess the extra info
126        if (JcrRepository.class.isAssignableFrom(repository.getClass())) {
127            final Map<String, String> config =
128                new GetClusterConfiguration().apply(repository);
129            assert (config != null);
130
131            for (final Map.Entry<String, String> entry : config.entrySet()) {
132                b.add(create(subject(), createURI(REPOSITORY_NAMESPACE + entry.getKey()),
133                        createLiteral(entry.getValue())));
134            }
135        }
136
137        // retrieve the metrics from the service
138        final SortedMap<String, Counter> counters = registryService.getMetrics().getCounters();
139        // and add the repository metrics to the RDF model
140        if (counters.containsKey("LowLevelStorageService.fixity-check-counter")) {
141            b.add(create(subject(), HAS_FIXITY_CHECK_COUNT.asNode(),
142                    createTypedLiteral(
143                            counters.get(
144                                    "org.fcrepo.services."
145                                            + "LowLevelStorageService."
146                                            + "fixity-check-counter")
147                                    .getCount()).asNode()));
148        }
149
150        if (counters.containsKey("LowLevelStorageService.fixity-error-counter")) {
151            b.add(create(subject(), HAS_FIXITY_ERROR_COUNT.asNode(),
152                    createTypedLiteral(
153                            counters.get(
154                                    "org.fcrepo.services."
155                                            + "LowLevelStorageService."
156                                            + "fixity-error-counter")
157                                    .getCount()).asNode()));
158        }
159
160        if (counters
161                .containsKey("LowLevelStorageService.fixity-repaired-counter")) {
162            b.add(create(subject(), HAS_FIXITY_REPAIRED_COUNT.asNode(),
163                    createTypedLiteral(
164                            counters.get(
165                                    "org.fcrepo.services."
166                                            + "LowLevelStorageService."
167                                            + "fixity-repaired-counter")
168                                    .getCount()).asNode()));
169        }
170
171        // offer all these accumulated triples
172        concat(b.build());
173    }
174
175}