/* * Copyright 2012 Research Studios Austria Forschungsges.m.b.H. * * 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. */ package won.node.service.impl; import org.apache.jena.datatypes.xsd.XSDDatatype; import org.apache.jena.query.Dataset; import org.apache.jena.query.DatasetFactory; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.Property; import org.apache.jena.rdf.model.Resource; import org.apache.jena.vocabulary.RDF; import org.apache.jena.vocabulary.RDFS; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.NoSuchMessageException; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Slice; import org.springframework.data.domain.SliceImpl; import org.springframework.data.domain.Sort; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import won.cryptography.rdfsign.WonKeysReaderWriter; import won.cryptography.service.CryptographyService; import won.protocol.exception.NoSuchConnectionException; import won.protocol.exception.NoSuchNeedException; import won.protocol.message.WonMessageType; import won.protocol.model.*; import won.protocol.repository.DatasetHolderRepository; import won.protocol.repository.MessageEventRepository; import won.protocol.repository.NeedRepository; import won.protocol.service.LinkedDataService; import won.protocol.service.NeedInformationService; import won.protocol.util.ConnectionModelMapper; import won.protocol.util.DefaultPrefixUtils; import won.protocol.util.NeedModelMapper; import won.protocol.util.RdfUtils; import won.protocol.vocabulary.LDP; import won.protocol.vocabulary.WON; import java.net.URI; import java.net.URISyntaxException; import java.util.*; /** * Creates rdf models from the relational database. * TODO: conform to: https://dvcs.w3.org/hg/ldpwg/raw-file/default/ldp-paging.html, especially for sorting */ public class LinkedDataServiceImpl implements LinkedDataService { final Logger logger = LoggerFactory.getLogger(getClass()); //prefix of a need resource private String needResourceURIPrefix; //prefix of a connection resource private String connectionResourceURIPrefix; //prefix of a event resource private String eventResourceURIPrefix; //prefix for URISs of RDF data private String dataURIPrefix; //prefix for URIs referring to real-world things private String resourceURIPrefix; //prefix for human readable pages private String pageURIPrefix; @Autowired private MessageEventRepository messageEventRepository; @Autowired private NeedRepository needRepository; @Autowired private DatasetHolderRepository datasetHolderRepository; //TODO: used to access/create event URIs for connection model rendering. Could be removed if events knew their URIs. private URIService uriService; @Autowired private NeedModelMapper needModelMapper; @Autowired private ConnectionModelMapper connectionModelMapper; @Autowired private CryptographyService cryptographyService; private String needProtocolEndpoint; private String matcherProtocolEndpoint; private String ownerProtocolEndpoint; private NeedInformationService needInformationService; private String activeMqEndpoint; private String activeMqNeedProtcolQueueName; private String activeMqOwnerProtcolQueueName; private String activeMqMatcherPrtotocolQueueName; private String activeMqMatcherProtocolTopicNameNeedCreated; private String activeMqMatcherProtocolTopicNameNeedActivated; private String activeMqMatcherProtocolTopicNameNeedDeactivated; @Transactional public Dataset listNeedURIs() { Model model = ModelFactory.createDefaultModel(); setNsPrefixes(model); Resource needListPageResource = null; Collection<URI> uris = null; uris = needInformationService.listNeedURIs(); needListPageResource = model.createResource(this.needResourceURIPrefix+"/"); for (URI needURI : uris) { model.add(model.createStatement(needListPageResource, RDFS.member, model.createResource(needURI.toString()))); } Dataset ret = newDatasetWithNamedModel(createDataGraphUriFromResource(needListPageResource), model); addBaseUriAndDefaultPrefixes(ret); return ret; } @Transactional(isolation = Isolation.READ_COMMITTED) public NeedInformationService.PagedResource<Dataset,URI> listNeedURIs(final int pageNum) { return listNeedURIs(pageNum, null, null); } @Transactional(isolation = Isolation.READ_COMMITTED) public NeedInformationService.PagedResource<Dataset,URI> listNeedURIsBefore(final URI need) { return listNeedURIsBefore(need, null, null); } @Transactional(isolation = Isolation.READ_COMMITTED) public NeedInformationService.PagedResource<Dataset,URI> listNeedURIsAfter(final URI need) { return listNeedURIsAfter(need, null, null); } @Transactional(isolation = Isolation.READ_COMMITTED) public NeedInformationService.PagedResource<Dataset,URI> listNeedURIs(final int pageNum, final Integer preferedSize, NeedState needState) { Slice<URI> slice = needInformationService.listNeedURIs(pageNum, preferedSize, needState); return toContainerPage(this.needResourceURIPrefix + "/", slice); } @Transactional(isolation = Isolation.READ_COMMITTED) public NeedInformationService.PagedResource<Dataset,URI> listNeedURIsBefore( final URI need, final Integer preferedSize, NeedState needState) { Slice<URI> slice = needInformationService.listNeedURIsBefore(need, preferedSize, needState); return toContainerPage(this.needResourceURIPrefix + "/", slice); } @Transactional(isolation = Isolation.READ_COMMITTED) public NeedInformationService.PagedResource<Dataset, URI> listNeedURIsAfter( final URI need, final Integer preferedSize, NeedState needState) { Slice<URI> slice = needInformationService.listNeedURIsAfter(need, preferedSize, needState); return toContainerPage(this.needResourceURIPrefix + "/", slice); } @Transactional(isolation = Isolation.READ_COMMITTED) public Dataset getNeedDataset(final URI needUri) throws NoSuchNeedException { Need need = needInformationService.readNeed(needUri); // load the dataset from storage Dataset dataset = need.getDatatsetHolder().getDataset(); Model metaModel = needModelMapper.toModel(need); Resource needResource = metaModel.getResource(needUri.toString()); // add connections Resource connectionsContainer = metaModel.createResource(need.getNeedURI().toString() + "/connections"); metaModel.add(metaModel.createStatement(needResource, WON.HAS_CONNECTIONS, connectionsContainer)); // add need event container Resource needEventContainer = metaModel.createResource(need.getNeedURI().toString()+"#events", WON.EVENT_CONTAINER); metaModel.add(metaModel.createStatement(needResource, WON.HAS_EVENT_CONTAINER, needEventContainer)); // add need event URIs Collection<MessageEventPlaceholder> messageEvents = need.getEventContainer().getEvents(); for (MessageEventPlaceholder messageEvent : messageEvents) { metaModel.add(metaModel.createStatement(needEventContainer, RDFS.member, metaModel.getResource(messageEvent.getMessageURI().toString()))); } // add WON node link needResource.addProperty(WON.HAS_WON_NODE, metaModel.createResource(this.resourceURIPrefix)); // add meta model to dataset String needMetaInformationURI = uriService.createNeedSysInfoGraphURI(needUri).toString(); dataset.addNamedModel(needMetaInformationURI, metaModel); addBaseUriAndDefaultPrefixes(dataset); return dataset; } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public Dataset getNeedDataset(final URI needUri, boolean deep, Integer deepLayerSize ) throws NoSuchNeedException, NoSuchConnectionException, NoSuchMessageException { Dataset dataset = getNeedDataset(needUri); if (deep) { Slice<URI> slice = needInformationService.listConnectionURIs(needUri, 1, deepLayerSize, null, null); NeedInformationService.PagedResource<Dataset, URI> connectionsResource = toContainerPage( this.uriService.createConnectionsURIForNeed(needUri).toString(), slice); addDeepConnectionData(connectionsResource.getContent(), slice.getContent()); RdfUtils.addDatasetToDataset(dataset, connectionsResource.getContent()); for (URI connectionUri : slice.getContent()) { NeedInformationService.PagedResource<Dataset,URI> eventsResource = listConnectionEventURIs( connectionUri, 1, deepLayerSize, null, true); RdfUtils.addDatasetToDataset(dataset, eventsResource.getContent()); } } return dataset; } @Transactional(isolation = Isolation.READ_COMMITTED) public Dataset getNodeDataset() { Model model = ModelFactory.createDefaultModel(); setNsPrefixes(model); Resource showNodePageResource = null; showNodePageResource = model.createResource(this.resourceURIPrefix); addNeedList(model, showNodePageResource); addProtocolEndpoints(model, showNodePageResource); Dataset ret = newDatasetWithNamedModel(createDataGraphUriFromResource(showNodePageResource), model); addBaseUriAndDefaultPrefixes(ret); addPublicKey(model, showNodePageResource); return ret; } private void addNeedList(Model model, Resource res) { res.addProperty(WON.HAS_NEED_LIST, model.createResource(this.needResourceURIPrefix)); } private void addPublicKey(Model model, Resource res) { WonKeysReaderWriter keyWriter = new WonKeysReaderWriter(); try { keyWriter.writeToModel(model, res, cryptographyService.getPublicKey(res.getURI())); } catch (Exception e) { logger.warn("No public key could be added to RDF for " + res.getURI()); } } //TODO: protocol endpoint specification in RDF model needs refactoring! private void addProtocolEndpoints(Model model, Resource res) { Resource blankNodeActiveMq = model.createResource(); res.addProperty(WON.SUPPORTS_WON_PROTOCOL_IMPL, blankNodeActiveMq); blankNodeActiveMq .addProperty(RDF.type, WON.WON_OVER_ACTIVE_MQ) .addProperty(WON.HAS_BROKER_URI, model.createResource(this.activeMqEndpoint)) .addProperty(WON.HAS_ACTIVEMQ_OWNER_PROTOCOL_QUEUE_NAME,this.activeMqOwnerProtcolQueueName,XSDDatatype.XSDstring) .addProperty(WON.HAS_ACTIVEMQ_NEED_PROTOCOL_QUEUE_NAME,this.activeMqNeedProtcolQueueName,XSDDatatype.XSDstring) .addProperty(WON.HAS_ACTIVEMQ_MATCHER_PROTOCOL_QUEUE_NAME,this.activeMqMatcherPrtotocolQueueName,XSDDatatype.XSDstring) .addProperty(WON.HAS_ACTIVEMQ_MATCHER_PROTOCOL_OUT_NEED_ACTIVATED_TOPIC_NAME, this.activeMqMatcherProtocolTopicNameNeedActivated,XSDDatatype.XSDstring) .addProperty(WON.HAS_ACTIVEMQ_MATCHER_PROTOCOL_OUT_NEED_DEACTIVATED_TOPIC_NAME,this.activeMqMatcherProtocolTopicNameNeedDeactivated,XSDDatatype.XSDstring) .addProperty(WON.HAS_ACTIVEMQ_MATCHER_PROTOCOL_OUT_NEED_CREATED_TOPIC_NAME,this.activeMqMatcherProtocolTopicNameNeedCreated,XSDDatatype.XSDstring) ; Resource blankNodeUriSpec = model.createResource(); res.addProperty(WON.HAS_URI_PATTERN_SPECIFICATION, blankNodeUriSpec); blankNodeUriSpec.addProperty(WON.HAS_NEED_URI_PREFIX, model.createLiteral(this.needResourceURIPrefix)); blankNodeUriSpec.addProperty(WON.HAS_CONNECTION_URI_PREFIX, model.createLiteral(this.connectionResourceURIPrefix)); blankNodeUriSpec.addProperty(WON.HAS_EVENT_URI_PREFIX, model.createLiteral(this.eventResourceURIPrefix)); } /*** * ETag-aware method for obtaining connection data. Currently does not take into account new events, only changes * to the connection itself. * @param connectionUri * @param includeEventContainer * @param includeLatestEvent * @param etag * @return */ @Override @Transactional(isolation = Isolation.READ_COMMITTED) public DataWithEtag<Dataset> getConnectionDataset(final URI connectionUri, final boolean includeEventContainer, final boolean includeLatestEvent, final String etag) { DataWithEtag<Connection> data = null; Connection connection = null; data = needInformationService.readConnection(connectionUri, etag); if (data.isNotFound()) { return DataWithEtag.dataNotFound(); } if (!data.isChanged()){ return DataWithEtag.dataNotChanged(data); } connection = data.getData(); String newEtag = data.getEtag(); // load the model from storage Model model = connectionModelMapper.toModel(connection); Model additionalData = connection.getDatasetHolder() == null ? null : connection.getDatasetHolder().getDataset().getDefaultModel(); setNsPrefixes(model); if (additionalData != null) { model.add(additionalData); } //model.setNsPrefix("", connection.getConnectionURI().toString()); //create connection member Resource connectionResource = model.getResource(connection.getConnectionURI().toString()); // add WON node link connectionResource.addProperty(WON.HAS_WON_NODE, model.createResource(this.resourceURIPrefix)); Dataset eventDataset = null; if (includeEventContainer) { //create event container and attach it to the member Resource eventContainer = model.createResource(connection.getConnectionURI().toString()+"/events"); connectionResource.addProperty(WON.HAS_EVENT_CONTAINER, eventContainer); eventContainer.addProperty(RDF.type, WON.EVENT_CONTAINER); if (includeLatestEvent) { //we add the latest event in the connection Slice<MessageEventPlaceholder> latestEvents = messageEventRepository.findByParentURIFetchDatasetEagerly(connectionUri, new PageRequest(0, 1, new Sort(Sort .Direction.DESC, "creationDate"))); if (latestEvents.hasContent()) { MessageEventPlaceholder event = latestEvents.getContent().get(0); //add the event's dataset eventDataset = setDefaults(event.getDatasetHolder().getDataset()); //connect the event to its container eventContainer.addProperty(RDFS.member, model.getResource(event.getMessageURI().toString())); } } DatasetHolder datasetHolder = connection.getDatasetHolder(); if (datasetHolder != null) { addAdditionalData(model, datasetHolder.getDataset().getDefaultModel(), connectionResource); } } Dataset connectionDataset = addBaseUriAndDefaultPrefixes(newDatasetWithNamedModel(createDataGraphUriFromResource (connectionResource), model)); RdfUtils.addDatasetToDataset(connectionDataset, eventDataset); return new DataWithEtag<>(connectionDataset,newEtag, etag); } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public Dataset listConnectionURIs(final boolean deep) throws NoSuchConnectionException { List<URI> uris = new ArrayList<URI>(needInformationService.listConnectionURIs()); NeedInformationService.PagedResource<Dataset, URI> containerPage = toContainerPage( this.connectionResourceURIPrefix + "/", new SliceImpl<URI>(uris)); if (deep) { addDeepConnectionData(containerPage.getContent(), uris); } return containerPage.getContent(); } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public NeedInformationService.PagedResource<Dataset, URI> listConnectionURIs(final int page, final Integer preferredSize, Date timeSpot, final boolean deep) throws NoSuchConnectionException { Slice<URI> slice = needInformationService.listConnectionURIs(page, preferredSize, timeSpot); NeedInformationService.PagedResource<Dataset, URI> containerPage = toContainerPage( this.connectionResourceURIPrefix + "/", slice); if (deep) { addDeepConnectionData(containerPage.getContent(), slice.getContent()); } return containerPage; } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public NeedInformationService.PagedResource<Dataset, URI> listConnectionURIsBefore( URI beforeConnURI, final Integer preferredSize, Date timeSpot, boolean deep) throws NoSuchConnectionException { Slice<URI> slice = needInformationService.listConnectionURIsBefore(beforeConnURI, preferredSize, timeSpot); NeedInformationService.PagedResource<Dataset, URI> containerPage = toContainerPage(this.connectionResourceURIPrefix + "/", slice); if (deep) { addDeepConnectionData(containerPage.getContent(), slice.getContent()); } return containerPage; } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public NeedInformationService.PagedResource<Dataset, URI> listConnectionURIsAfter( URI afterConnURI, final Integer preferredSize, Date timeSpot, boolean deep) throws NoSuchConnectionException { Slice<URI> slice = needInformationService.listConnectionURIsAfter(afterConnURI, preferredSize, timeSpot); NeedInformationService.PagedResource<Dataset, URI> containerPage = toContainerPage( this.connectionResourceURIPrefix + "/", slice); if (deep) { addDeepConnectionData(containerPage.getContent(), slice.getContent()); } return containerPage; } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public Dataset listConnectionURIs(final URI needURI, boolean deep, boolean addMetadata) throws NoSuchNeedException, NoSuchConnectionException { List<URI> uris = new ArrayList<URI>(needInformationService.listConnectionURIs(needURI)); URI connectionsUri = this.uriService.createConnectionsURIForNeed(needURI); NeedInformationService.PagedResource<Dataset, URI> containerPage = toContainerPage(connectionsUri.toString(), new SliceImpl<URI>(uris)); if (deep) { addDeepConnectionData(containerPage.getContent(), uris); } if (addMetadata){ addConnectionMetadata(containerPage.getContent(), needURI, connectionsUri); } return containerPage.getContent(); } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public NeedInformationService.PagedResource<Dataset, URI> listConnectionURIs( final int page, final URI needURI, final Integer preferredSize, final WonMessageType messageType, final Date timeSpot, boolean deep, boolean addMetadata) throws NoSuchNeedException, NoSuchConnectionException { Slice<URI> slice = needInformationService.listConnectionURIs(needURI, page, preferredSize, messageType, timeSpot); URI connectionsUri = this.uriService.createConnectionsURIForNeed(needURI); NeedInformationService.PagedResource<Dataset, URI> containerPage = toContainerPage(connectionsUri.toString(), slice); if (deep) { addDeepConnectionData(containerPage.getContent(), slice.getContent()); } if (addMetadata){ addConnectionMetadata(containerPage.getContent(), needURI, connectionsUri); } return containerPage; } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public NeedInformationService.PagedResource<Dataset, URI> listConnectionURIsBefore(final URI needURI, URI beforeEventURI, final Integer preferredSize, final WonMessageType messageType, final Date timeSpot, boolean deep, boolean addMetadata) throws NoSuchNeedException, NoSuchConnectionException { Slice<URI> slice = needInformationService.listConnectionURIsBefore( needURI, beforeEventURI, preferredSize, messageType, timeSpot); URI connectionsUri = this.uriService.createConnectionsURIForNeed(needURI); NeedInformationService.PagedResource<Dataset, URI> containerPage = toContainerPage(connectionsUri.toString(), slice); if (deep) { addDeepConnectionData(containerPage.getContent(), slice.getContent()); } if (addMetadata){ addConnectionMetadata(containerPage.getContent(), needURI, connectionsUri); } return containerPage; } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public NeedInformationService.PagedResource<Dataset, URI> listConnectionURIsAfter(final URI needURI, URI resumeConnURI, final Integer preferredSize, final WonMessageType messageType, final Date timeSpot, boolean deep, boolean addMetadata) throws NoSuchNeedException, NoSuchConnectionException { Slice<URI> slice = needInformationService.listConnectionURIsAfter( needURI, resumeConnURI, preferredSize, messageType, timeSpot); URI connectionsUri = this.uriService.createConnectionsURIForNeed(needURI); NeedInformationService.PagedResource<Dataset, URI> containerPage = toContainerPage( connectionsUri.toString(), slice); if (deep) { addDeepConnectionData(containerPage.getContent(), slice.getContent()); } if (addMetadata){ addConnectionMetadata(containerPage.getContent(), needURI, connectionsUri); } return containerPage; } private void addConnectionMetadata(final Dataset content, URI needURI, URI containerURI) { Model model = content.getNamedModel(createDataGraphUriFromUri(containerURI) ); List<Object[]> connectionCountsPerState = needRepository.getCountsPerConnectionState(needURI); Resource containerResource = model.getResource(containerURI.toString()); for (Object[] countForState : connectionCountsPerState){ ConnectionState stateName = (ConnectionState) countForState[0]; Long count = (Long) countForState[1]; Property countProperty = getRdfPropertyForState(stateName); if (countProperty == null) { logger.warn("did not recognize connection state " + stateName); continue; } containerResource.addProperty(countProperty, Integer.toString(count.intValue()), XSDDatatype.XSDint); } } private Property getRdfPropertyForState(ConnectionState state) { switch (state){ case SUGGESTED: return WON.HAS_SUGGESTED_COUNT; case REQUEST_RECEIVED: return WON.HAS_REQUEST_RECEIVED_COUNT; case REQUEST_SENT: return WON.HAS_REQUEST_SENT_COUNT; case CONNECTED: return WON.HAS_CONNECTED_COUNT; case CLOSED: return WON.HAS_CLOSED_COUNT; } return null; } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public Dataset listConnectionEventURIs(final URI connectionUri) throws NoSuchConnectionException { return listConnectionEventURIs(connectionUri, false); } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public Dataset listConnectionEventURIs(final URI connectionUri, boolean deep) throws NoSuchConnectionException { Model model = ModelFactory.createDefaultModel(); setNsPrefixes(model); Connection connection = needInformationService.readConnection(connectionUri); Resource eventContainer = model.createResource(connection.getConnectionURI().toString() + "/events", WON.EVENT_CONTAINER); // add the events with the new format (only the URI, no content) List<MessageEventPlaceholder> connectionEvents = messageEventRepository.findByParentURI(connectionUri); Dataset eventsContainerDataset = newDatasetWithNamedModel(createDataGraphUriFromResource(eventContainer), model); addBaseUriAndDefaultPrefixes(eventsContainerDataset); for (MessageEventPlaceholder event : connectionEvents) { model.add(model.createStatement(eventContainer, RDFS.member, model.getResource(event.getMessageURI().toString()))); if (deep) { Dataset eventDataset = event.getDatasetHolder().getDataset(); RdfUtils.addDatasetToDataset(eventsContainerDataset, eventDataset); } } return eventsContainerDataset; } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public NeedInformationService.PagedResource<Dataset,URI> listConnectionEventURIs(final URI connectionUri, final int pageNum, Integer preferedSize, WonMessageType msgType, boolean deep) throws NoSuchConnectionException { Slice<MessageEventPlaceholder> slice = needInformationService.listConnectionEvents(connectionUri, pageNum, preferedSize, msgType); NeedInformationService.PagedResource<Dataset,URI> containerPage = eventsToContainerPage( this.uriService.createEventsURIForConnection(connectionUri).toString(), slice, deep); return containerPage; } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public NeedInformationService.PagedResource<Dataset,URI> listConnectionEventURIsAfter( final URI connectionUri, final URI msgURI, Integer preferedSize, WonMessageType msgType, boolean deep) throws NoSuchConnectionException { Slice<MessageEventPlaceholder> slice = needInformationService.listConnectionEventsAfter( connectionUri, msgURI, preferedSize, msgType); NeedInformationService.PagedResource<Dataset,URI> containerPage = eventsToContainerPage(this.uriService .createEventsURIForConnection (connectionUri).toString(), slice, deep); return containerPage; } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public NeedInformationService.PagedResource<Dataset,URI> listConnectionEventURIsBefore( final URI connectionUri, final URI msgURI, Integer preferedSize, WonMessageType msgType, boolean deep) throws NoSuchConnectionException { Slice<MessageEventPlaceholder> slice = needInformationService.listConnectionEventsBefore( connectionUri, msgURI, preferedSize, msgType); NeedInformationService.PagedResource<Dataset,URI> containerPage = eventsToContainerPage(this.uriService.createEventsURIForConnection (connectionUri).toString(), slice, deep); return containerPage; } @Transactional(isolation = Isolation.READ_COMMITTED) private Dataset setDefaults(Dataset dataset) { if (dataset == null) return null; DefaultPrefixUtils.setDefaultPrefixes(dataset.getDefaultModel()); addBaseUriAndDefaultPrefixes(dataset); return dataset; } @Override @Transactional(isolation = Isolation.READ_COMMITTED) public DataWithEtag<Dataset> getDatasetForUri(URI datasetUri, String etag) { Integer version = etag == null ? -1: Integer.valueOf(etag); DatasetHolder datasetHolder = datasetHolderRepository.findOneByUri(datasetUri); if (datasetHolder == null) { return DataWithEtag.dataNotFound(); } if (version.intValue() == datasetHolder.getVersion()){ return DataWithEtag.dataNotChanged(etag); } Dataset dataset = datasetHolder.getDataset(); DefaultPrefixUtils.setDefaultPrefixes(dataset.getDefaultModel()); addBaseUriAndDefaultPrefixes(dataset); return new DataWithEtag<Dataset>(dataset, Integer.toString(datasetHolder.getVersion()), etag); } private String createDataGraphUriFromResource(Resource needListPageResource) { URI uri = URI.create(needListPageResource.getURI()); return createDataGraphUriFromUri(uri); } private String createDataGraphUriFromUri(final URI uri) { try { URI ret = new URI(uri.getScheme(), uri.getHost(), uri.getPath(), uri.getQuery(), "data"); return ret.toString(); } catch (URISyntaxException e) { return uri.toString() + "#data"; } } private Dataset newDatasetWithNamedModel(String graphUri, Model model) { Dataset dataset = DatasetFactory.createGeneral(); dataset.addNamedModel(graphUri, model); return dataset; } private void addAdditionalData(final Model targetModel, Model fromModel, final Resource targetResource) { if (fromModel != null && fromModel.size() > 0) { Resource additionalData = fromModel.createResource(); //TODO: check if the statement below is now necessary //RdfUtils.replaceBaseResource(additionalDataModel, additionalData); targetModel.add(targetModel.createStatement(targetResource, WON.HAS_ADDITIONAL_DATA, additionalData)); targetModel.add(fromModel); } } private String addPageQueryString(String uri, int page) { //TODO: simple implementation for adding page number to uri - breaks as soon as other query strings are present! return uri + "?page=" + page; } /** * @deprecated the method returns the paged resource description according to Linked Data Platform Draft 2013 * https://www.w3.org/TR/2013/WD-ldp-20130730/. As of state Feb 2016 (https://www.w3.org/TR/2015/REC-ldp-20150226/) * the paged resource should not contain any paging information as part of resource description, this information * is conveyed vie HEADERs. Therefore, this method should no longer be used. */ @Deprecated private Resource createPage(final Model model, final String containerURI, final int pageNum, NeedInformationService.Page page) { String containerPageURI = addPageQueryString(containerURI, pageNum); Resource containerPageResource = model.createResource(containerPageURI); Resource containerResource = model.createResource(containerURI); model.add(model.createStatement(containerPageResource, RDF.type, LDP.PAGE)); model.add(model.createStatement(containerPageResource, LDP.PAGE_OF, containerResource)); model.add(model.createStatement(containerPageResource, RDF.type, LDP.CONTAINER)); Resource containerNextPageResource = null; //assume last page if we didn't fetch pageSize uris if (page.hasNext()) { containerNextPageResource = model.createResource(addPageQueryString(containerURI, pageNum + 1)); model.add(model.createStatement(containerPageResource, LDP.NEXT_PAGE, containerNextPageResource)); } return containerPageResource; } private void setNsPrefixes(final Model model) { DefaultPrefixUtils.setDefaultPrefixes(model); } /** * Adds the specified URI as the default prefix for each model in the dataset and * return the dataset. * @param dataset * @return */ private Dataset addBaseUriAndDefaultPrefixes(Dataset dataset){ setNsPrefixes(dataset.getDefaultModel()); addPrefixForSpecialResources(dataset, "local", this.resourceURIPrefix); addPrefixForSpecialResources(dataset, "need", this.needResourceURIPrefix); addPrefixForSpecialResources(dataset, "event", this.eventResourceURIPrefix); addPrefixForSpecialResources(dataset, "conn", this.connectionResourceURIPrefix); return dataset; } private void addPrefixForSpecialResources(Dataset dataset, String prefix, String uri) { if (uri == null) return; //ignore if no uri specified //the prefix (prefix of all local URIs must end with a slash or a hash, otherwise, //it will never be used by RDF serializations. Force that. if (!uri.endsWith("/") && !uri.endsWith("#")) { uri += "/"; } dataset.getDefaultModel().getGraph().getPrefixMapping().setNsPrefix(prefix, uri); } private NeedInformationService.PagedResource<Dataset,URI> toContainerPage(String containerUri, Slice<URI> slice) { List<URI> uris = slice.getContent(); URI resumeBefore = null; URI resumeAfter = null; if (slice.getSort() != null && !uris.isEmpty()) { Iterator<Sort.Order> sortOrders = slice.getSort().iterator(); if (sortOrders.hasNext()) { Sort.Order sortOrder = sortOrders.next(); if (sortOrder.getDirection() == Sort.Direction.ASC) { resumeBefore = uris.get(0); resumeAfter = uris.get(uris.size() - 1); } else { resumeBefore = uris.get(uris.size() - 1); resumeAfter = uris.get(0); } } } Model model = ModelFactory.createDefaultModel(); setNsPrefixes(model); Resource needListPageResource = null; needListPageResource = model.createResource(containerUri); for (URI needURI : uris) { model.add(model.createStatement(needListPageResource, RDFS.member, model.createResource(needURI.toString()))); } Dataset dataset = newDatasetWithNamedModel(createDataGraphUriFromResource(needListPageResource), model); addBaseUriAndDefaultPrefixes(dataset); NeedInformationService.PagedResource<Dataset,URI> containerPage = new NeedInformationService.PagedResource (dataset, resumeBefore, resumeAfter); return containerPage; } /** * Returns a container resource with the messageUris of all MessageEventPlaceholder objects in the slice. * If deep == true, the event datasets are added, too. * @param containerUri * @param slice * @param deep * @return */ private NeedInformationService.PagedResource<Dataset,URI> eventsToContainerPage(String containerUri, Slice<MessageEventPlaceholder> slice, boolean deep) { List<MessageEventPlaceholder> events = slice.getContent(); URI resumeBefore = null; URI resumeAfter = null; if (slice.getSort() != null && !events.isEmpty()) { Iterator<Sort.Order> sortOrders = slice.getSort().iterator(); if (sortOrders.hasNext()) { Sort.Order sortOrder = sortOrders.next(); if (sortOrder.getDirection() == Sort.Direction.ASC) { resumeBefore = events.get(0).getMessageURI(); resumeAfter = events.get(events.size() - 1).getMessageURI(); } else { resumeBefore = events.get(events.size() - 1).getMessageURI(); resumeAfter = events.get(0).getMessageURI(); } } } Model model = ModelFactory.createDefaultModel(); setNsPrefixes(model); Resource needListPageResource = null; needListPageResource = model.createResource(containerUri); DatasetHolderAggregator aggregator = new DatasetHolderAggregator(); for (MessageEventPlaceholder event : events) { model.add(model.createStatement(needListPageResource, RDFS.member, model.createResource(event.getMessageURI().toString()))); if (deep) { aggregator.appendDataset(event.getDatasetHolder()); } } Dataset dataset = aggregator.aggregate(); dataset.addNamedModel(createDataGraphUriFromResource(needListPageResource), model); addBaseUriAndDefaultPrefixes(dataset); NeedInformationService.PagedResource<Dataset,URI> containerPage = new NeedInformationService.PagedResource (dataset, resumeBefore, resumeAfter); return containerPage; } public void addDeepConnectionData(Dataset dataset, List<URI> connectionURIs) throws NoSuchConnectionException { //add the connection model for each connection URI for (URI connectionURI : connectionURIs) { DataWithEtag<Dataset> connectionDataset = getConnectionDataset(connectionURI, true, true, null); RdfUtils.addDatasetToDataset(dataset, connectionDataset.getData()); } } public void setNeedResourceURIPrefix(final String needResourceURIPrefix) { this.needResourceURIPrefix = needResourceURIPrefix; } public void setConnectionResourceURIPrefix(final String connectionResourceURIPrefix) { this.connectionResourceURIPrefix = connectionResourceURIPrefix; } public void setEventResourceURIPrefix(final String eventResourceURIPrefix) { this.eventResourceURIPrefix = eventResourceURIPrefix; } public void setDataURIPrefix(final String dataURIPrefix) { this.dataURIPrefix = dataURIPrefix; } public void setResourceURIPrefix(final String resourceURIPrefix) { this.resourceURIPrefix = resourceURIPrefix; } public void setNeedInformationService(final NeedInformationService needInformationService) { this.needInformationService = needInformationService; } public void setNeedProtocolEndpoint(final String needProtocolEndpoint) { this.needProtocolEndpoint = needProtocolEndpoint; } public void setMatcherProtocolEndpoint(final String matcherProtocolEndpoint) { this.matcherProtocolEndpoint = matcherProtocolEndpoint; } public void setOwnerProtocolEndpoint(final String ownerProtocolEndpoint) { this.ownerProtocolEndpoint = ownerProtocolEndpoint; } public void setPageURIPrefix(final String pageURIPrefix) { this.pageURIPrefix = pageURIPrefix; } public void setUriService(URIService uriService) { this.uriService = uriService; } public void setActiveMqOwnerProtcolQueueName(String activeMqOwnerProtcolQueueName) { this.activeMqOwnerProtcolQueueName = activeMqOwnerProtcolQueueName; } public void setActiveMqNeedProtcolQueueName(String activeMqNeedProtcolQueueName) { this.activeMqNeedProtcolQueueName = activeMqNeedProtcolQueueName; } public void setActiveMqMatcherPrtotocolQueueName(String activeMqMatcherPrtotocolQueueName) { this.activeMqMatcherPrtotocolQueueName = activeMqMatcherPrtotocolQueueName; } public void setActiveMqEndpoint(String activeMqEndpoint) { this.activeMqEndpoint = activeMqEndpoint; } public void setActiveMqMatcherProtocolTopicNameNeedCreated(final String activeMqMatcherProtocolTopicNameNeedCreated) { this.activeMqMatcherProtocolTopicNameNeedCreated = activeMqMatcherProtocolTopicNameNeedCreated; } public void setActiveMqMatcherProtocolTopicNameNeedActivated(final String activeMqMatcherProtocolTopicNameNeedActivated) { this.activeMqMatcherProtocolTopicNameNeedActivated = activeMqMatcherProtocolTopicNameNeedActivated; } public void setActiveMqMatcherProtocolTopicNameNeedDeactivated(final String activeMqMatcherProtocolTopicNameNeedDeactivated) { this.activeMqMatcherProtocolTopicNameNeedDeactivated = activeMqMatcherProtocolTopicNameNeedDeactivated; } }