org.ldp4j.application.kernel.engine.DefaultExistingPublicResource.java Source code

Java tutorial

Introduction

Here is the source code for org.ldp4j.application.kernel.engine.DefaultExistingPublicResource.java

Source

/**
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   This file is part of the LDP4j Project:
 *     http://www.ldp4j.org/
 *
 *   Center for Open Middleware
 *     http://www.centeropenmiddleware.com/
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Copyright (C) 2014-2016 Center for Open Middleware.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Licensed under the Apache 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.apache.org/licenses/LICENSE-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.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Artifact    : org.ldp4j.framework:ldp4j-application-kernel-core:0.2.1
 *   Bundle      : ldp4j-application-kernel-core-0.2.1.jar
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 */
package org.ldp4j.application.kernel.engine;

import java.net.URI;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.ldp4j.application.data.DataSet;
import org.ldp4j.application.data.DataSets;
import org.ldp4j.application.data.Individual;
import org.ldp4j.application.data.ManagedIndividualId;
import org.ldp4j.application.data.Property;
import org.ldp4j.application.data.constraints.Constraints;
import org.ldp4j.application.data.validation.ValidationConstraintFactory;
import org.ldp4j.application.data.validation.ValidationReport;
import org.ldp4j.application.data.validation.Validator;
import org.ldp4j.application.data.validation.Validator.ValidatorBuilder;
import org.ldp4j.application.engine.context.ApplicationExecutionException;
import org.ldp4j.application.engine.context.ContentPreferences;
import org.ldp4j.application.engine.context.PublicBasicContainer;
import org.ldp4j.application.engine.context.PublicDirectContainer;
import org.ldp4j.application.engine.context.PublicIndirectContainer;
import org.ldp4j.application.engine.context.PublicRDFSource;
import org.ldp4j.application.engine.context.PublicResource;
import org.ldp4j.application.engine.context.PublicResourceVisitor;
import org.ldp4j.application.ext.InconsistentContentException;
import org.ldp4j.application.ext.InvalidContentException;
import org.ldp4j.application.ext.Query;
import org.ldp4j.application.kernel.endpoint.Endpoint;
import org.ldp4j.application.kernel.resource.Attachment;
import org.ldp4j.application.kernel.resource.Resource;
import org.ldp4j.application.kernel.resource.ResourceId;
import org.ldp4j.application.kernel.template.AttachedTemplate;
import org.ldp4j.application.vocabulary.LDP;
import org.ldp4j.application.vocabulary.RDF;

import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;

abstract class DefaultExistingPublicResource extends DefaultPublicResource {

    private static final class AdditionalValidationConstraintConfigurator implements PublicResourceVisitor<Void> {

        private final DataSet metadata;
        private final Individual<?, ?> individual;
        private final ValidatorBuilder builder;

        private AdditionalValidationConstraintConfigurator(DataSet metadata, Individual<?, ?> individual,
                ValidatorBuilder builder) {
            this.metadata = metadata;
            this.individual = individual;
            this.builder = builder;
        }

        @Override
        public Void visitRDFSource(PublicRDFSource resource) {
            // Nothing to do
            return null;
        }

        @Override
        public Void visitBasicContainer(PublicBasicContainer resource) {
            // Nothing to do
            return null;
        }

        @Override
        public Void visitDirectContainer(PublicDirectContainer resource) {
            ((DefaultPublicDirectContainer) resource).configureMemberValidationConstraints(builder, individual,
                    metadata);
            return null;
        }

        @Override
        public Void visitIndirectContainer(PublicIndirectContainer resource) {
            ((DefaultPublicIndirectContainer) resource).configureMemberValidationConstraints(builder, individual,
                    metadata);
            return null;
        }
    }

    private static final class AdditionalMetadataPopulator implements PublicResourceVisitor<Void> {

        private final Context ctx;
        private final ContentPreferences contentPreferences;
        private final Individual<?, ?> individual;

        private AdditionalMetadataPopulator(Context ctx, ContentPreferences contentPreferences,
                Individual<?, ?> individual) {
            this.ctx = ctx;
            this.contentPreferences = contentPreferences;
            this.individual = individual;
        }

        @Override
        public Void visitRDFSource(PublicRDFSource resource) {
            // Nothing to do
            return null;
        }

        @Override
        public Void visitBasicContainer(PublicBasicContainer resource) {
            // Nothing to do
            return null;
        }

        @Override
        public Void visitDirectContainer(PublicDirectContainer resource) {
            ((DefaultPublicDirectContainer) resource).fillInMemberMetadata(contentPreferences, individual, ctx);
            return null;
        }

        @Override
        public Void visitIndirectContainer(PublicIndirectContainer resource) {
            ((DefaultPublicIndirectContainer) resource).fillInMemberMetadata(contentPreferences, individual, ctx);
            return null;
        }
    }

    private static final URI HAS_ATTACHMENT = URI.create("http://www.ldp4j.org/ns/application#hasAttachment");

    private final ManagedIndividualId individualId;

    protected DefaultExistingPublicResource(DefaultApplicationContext applicationContext, Endpoint endpoint) {
        super(applicationContext, endpoint);
        this.individualId = ManagedIndividualId.createId(id().name(), id().templateId());
    }

    @Override
    public final ManagedIndividualId individualId() {
        return this.individualId;
    }

    @Override
    public final Map<String, PublicResource> attachments() {
        Map<String, PublicResource> result = new HashMap<String, PublicResource>();
        for (Attachment attachment : resolveAs(Resource.class).attachments()) {
            result.put(attachment.id(), createResource(attachment.resourceId()));
        }
        return result;
    }

    @Override
    public final DataSet entity(ContentPreferences contentPreferences) throws ApplicationExecutionException {
        DataSet dataSet = resourceData(contentPreferences);
        DataSet representation = DataSets.createDataSet(id().name());
        DataSets.merge(dataSet, representation);
        Context ctx = new Context(representation);
        fillInMetadata(contentPreferences, ctx.newIndividual(individualId()), ctx);
        return representation;
    }

    @Override
    public final DataSet query(Query query, ContentPreferences contentPreferences)
            throws ApplicationExecutionException {
        return applicationContext().query(endpoint(), query);
    }

    @Override
    public final void delete() throws ApplicationExecutionException {
        applicationContext().deleteResource(endpoint());
    }

    @Override
    public final void modify(DataSet dataSet) throws ApplicationExecutionException {
        DataSet metadata = metadata();
        try {
            // First check that the framework/protocol metadata has not been messed
            // around
            validate(dataSet, metadata);

            // Second, remove the framework/protocol metadata from the
            // representation that will be handed to the application
            DataSets.remove(metadata, dataSet);

            // Third, request the modification using the cleansed and validated data
            applicationContext().modifyResource(endpoint(), dataSet);
        } catch (InvalidContentException error) {
            applicationContext().registerContentFailure(endpoint(), error);
            throw new ApplicationExecutionException("Protocol/framework managed metadata validation failure",
                    error);
        }
    }

    @Override
    public DataSet getConstraintReport(String constraintsId) throws ApplicationExecutionException {
        return applicationContext().getConstraintReport(endpoint(), constraintsId);
    }

    @Override
    protected DataSet metadata() {
        DataSet metadata = DataSets.createDataSet(id().name());

        Context ctx = new Context(metadata);
        ManagedIndividualId id = individualId();

        fillInMetadata(ContentPreferences.defaultPreferences(), ctx.newIndividual(id), ctx);
        return metadata;
    }

    @Override
    protected DataSet resourceData(ContentPreferences contentPreferences) throws ApplicationExecutionException {
        return applicationContext().getResource(endpoint());
    }

    @Override
    protected final ResourceId id() {
        return endpoint().resourceId();
    }

    @Override
    protected void fillInMetadata(ContentPreferences contentPreferences, final Individual<?, ?> individual,
            final Context ctx) {
        individual.addValue(ctx.property(RDF.TYPE), ctx.reference(LDP.RESOURCE));
        for (Entry<String, PublicResource> entry : attachments().entrySet()) {
            AttachedTemplate attachedTemplate = template().attachedTemplate(entry.getKey());
            individual.addValue(attachedTemplate.predicate().or(HAS_ATTACHMENT),
                    ctx.newIndividual(entry.getValue()));
            populateAdditionalMetadata(contentPreferences, individual, ctx, entry.getValue());
        }
    }

    private void populateAdditionalMetadata(final ContentPreferences contentPreferences,
            final Individual<?, ?> individual, final Context ctx, PublicResource resource) {
        resource.accept(new AdditionalMetadataPopulator(ctx, contentPreferences, individual));
    }

    @Override
    protected void configureValidationConstraints(ValidatorBuilder builder, Individual<?, ?> individual,
            DataSet metadata) {
        builder.withPropertyConstraint(
                ValidationConstraintFactory.mandatoryPropertyValues(individual.property(RDF.TYPE.as(URI.class))));
        Multimap<URI, AttachedTemplate> attachmentMap = LinkedHashMultimap.create();
        for (AttachedTemplate attachedTemplate : template().attachedTemplates()) {
            URI propertyId = attachedTemplate.predicate().or(HAS_ATTACHMENT);
            attachmentMap.put(propertyId, attachedTemplate);
        }
        for (Entry<URI, Collection<AttachedTemplate>> entry : attachmentMap.asMap().entrySet()) {
            URI propertyId = entry.getKey();
            Property property = individual.property(propertyId);
            if (property != null) {
                configurePropertyValidationConstraints(builder, individual, metadata, property, entry.getValue());
            } else {
                builder.withPropertyConstraint(
                        ValidationConstraintFactory.readOnlyProperty(individual.id(), propertyId));
            }
        }
    }

    private void configurePropertyValidationConstraints(ValidatorBuilder builder, Individual<?, ?> individual,
            DataSet metadata, Property property, Collection<AttachedTemplate> value) {
        builder.withPropertyConstraint(ValidationConstraintFactory.readOnlyProperty(property));
        for (AttachedTemplate attachedTemplate : value) {
            PublicResource resource = attachments().get(attachedTemplate.id());
            if (resource != null) {
                configureAdditionalValidationConstraints(builder, individual, metadata, resource);
            }
        }
    }

    private void configureAdditionalValidationConstraints(final ValidatorBuilder builder,
            final Individual<?, ?> individual, final DataSet metadata, PublicResource resource) {
        resource.accept(new AdditionalValidationConstraintConfigurator(metadata, individual, builder));
    }

    private void validate(DataSet dataSet, DataSet metadata) throws InvalidContentException {
        ManagedIndividualId id = individualId();
        Individual<?, ?> individual = metadata.individualOfId(id);

        ValidatorBuilder builder = Validator.builder();

        configureValidationConstraints(builder, individual, metadata);

        Validator validator = builder.build();

        ValidationReport report = validator.validate(dataSet);
        if (!report.isValid()) {
            // TODO: Add validation constraints
            Constraints constraints = Constraints.constraints();
            throw new InconsistentContentException(
                    "Protocol/framework managed metadata validation failed: " + report.validationFailures(),
                    constraints);
        }
    }

    @Override
    protected final ManagedIndividualId indirectIndividualId() {
        ManagedIndividualId result = this.individualId;
        URI indirectId = resolveAs(Resource.class).indirectId();
        if (indirectId != null) {
            result = ManagedIndividualId.createId(indirectId, result);
        }
        return result;
    }

}