/*
22 * Copyright 2013, 2014, 2015 EnergyOS.org
*
* 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 org.energyos.espi.common.service.impl;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import org.energyos.espi.common.domain.ApplicationInformation;
import org.energyos.espi.common.domain.ElectricPowerQualitySummary;
import org.energyos.espi.common.domain.ElectricPowerUsageSummary;
import org.energyos.espi.common.domain.IdentifiedObject;
import org.energyos.espi.common.domain.IntervalBlock;
import org.energyos.espi.common.domain.MeterReading;
import org.energyos.espi.common.domain.ReadingType;
import org.energyos.espi.common.domain.TimeConfiguration;
import org.energyos.espi.common.domain.UsagePoint;
import org.energyos.espi.common.models.atom.EntryType;
import org.energyos.espi.common.models.atom.LinkType;
import org.energyos.espi.common.service.EntryProcessorService;
import org.energyos.espi.common.service.ResourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Transactional(rollbackFor = { javax.xml.bind.JAXBException.class }, noRollbackFor = {
javax.persistence.NoResultException.class,
org.springframework.dao.EmptyResultDataAccessException.class })
@Service
public class EntryProcessorServiceImpl implements EntryProcessorService {
@Autowired
private ResourceService resourceService;
public EntryType process(EntryType entry) {
convert(entry);
for (IdentifiedObject resource : entry.getContent().getResources()) {
try {
IdentifiedObject existingResource = resourceService.findByUUID(
resource.getUUID(), resource.getClass());
existingResource = resourceService.merge(existingResource);
// merge the new into the old and throw the new away
//
existingResource.merge(resource);
// now put the existing resource back into the structure so it
// will
// be available for later processing
if (existingResource instanceof UsagePoint) {
entry.getContent().setUsagePoint(
(UsagePoint) existingResource);
}
if (existingResource instanceof MeterReading) {
entry.getContent().setMeterReading(
(MeterReading) existingResource);
}
if (existingResource instanceof IntervalBlock) {
// System.out.printf("*****We have an existing IntervalBlock??: %s\n",
// existingResource.toString());
List<IntervalBlock> intervalBlocks = entry.getContent()
.getIntervalBlocks();
List<IntervalBlock> newList = new ArrayList<IntervalBlock>();
Iterator<IntervalBlock> blocks = intervalBlocks.iterator();
while (blocks.hasNext()) {
IntervalBlock bl = blocks.next();
if (bl.getUUID().equals(existingResource.getUUID())) {
existingResource.merge(bl);
newList.add((IntervalBlock) existingResource);
} else {
newList.add(bl);
}
}
}
if (existingResource instanceof ReadingType) {
entry.getContent().setReadingType(
(ReadingType) existingResource);
}
if (existingResource instanceof TimeConfiguration) {
entry.getContent().setLocalTimeParameters(
(TimeConfiguration) existingResource);
}
if (existingResource instanceof ElectricPowerUsageSummary) {
entry.getContent().setElectricPowerUsageSummary(
(ElectricPowerUsageSummary) existingResource);
}
if (existingResource instanceof ElectricPowerQualitySummary) {
entry.getContent().setElectricPowerQualitySummary(
(ElectricPowerQualitySummary) existingResource);
}
if (existingResource instanceof ApplicationInformation) {
entry.getContent().setApplicationInformation(
(ApplicationInformation) existingResource);
}
link(existingResource);
} catch (EmptyResultDataAccessException x) {
resourceService.persist(resource);
link(resource);
}
}
return entry;
}
// the private functions that do the work
//
private void link(IdentifiedObject resource) {
linkUp(resource);
linkUpMember(resource);
linkRelatedCollection(resource);
}
// Copy the entry attributes into the resource attributes
//
public void convert(EntryType entry) {
// support for entries that contain multiple resources has been added here
// the result of entry.getContent().getResources()) can return a mixed back of resources, only one of which
// will have appropriate UUID and self references - the rest will need UUIDs and self references created
// NOTE: that this means, in effect, that if the resources types MUST have the same up reference (because there
// is only one available in the <entry> structure itself
Integer resourceCount = 0;
for (IdentifiedObject resource : entry.getContent().getResources()) {
resourceCount++;
if (resourceCount > 1) {
// make a new UUID and stash it in the entry
entry.setId(UUID.randomUUID().toString());
}
resource.setMRID(entry.getId());
for (LinkType link : entry.getLinks()) {
if (link.getRel().equals(LinkType.SELF)) {
LinkType newLink = link;
if (resourceCount >1) {
// it doesn't mater what this is, except that it must be
// unique - the UUID works just fine
newLink = new LinkType();
newLink.setHref(entry.getId());
newLink.setRel(LinkType.SELF);
}
resource.setSelfLink(newLink);
}
if (link.getRel().equals(LinkType.UP))
resource.setUpLink(link);
if (link.getRel().equals(LinkType.RELATED))
resource.getRelatedLinks().add(link);
}
resource.setDescription(entry.getTitle());
resource.setPublished(entry.getPublished().getValue()
.toGregorianCalendar());
resource.setUpdated(entry.getUpdated().getValue()
.toGregorianCalendar());
}
}
// Establish the rel="up" links into the parent collections
//
private void linkUp(IdentifiedObject resource) {
if (resource.getUpLink() != null) {
List<IdentifiedObject> parents = resourceService
.findByAllParentsHref(resource.getUpLink().getHref(),
resource);
for (IdentifiedObject parent : parents) {
// add the parent to the transaction
resourceService.merge(parent);
// add the resource to the parent collection
resource.setUpResource(parent);
}
}
}
// Establish the rel="related" links to the associated resources
//
private void linkUpMember(IdentifiedObject resource) {
if (resource.getSelfLink() != null) {
List<IdentifiedObject> parents = resourceService
.findByAllParentsHref(resource.getSelfLink().getHref(),
resource);
for (IdentifiedObject parent : parents) {
// put the existing resource in the transaction
resourceService.merge(parent);
// Based on the kind of resource, do the appropriate fixup
if (resource instanceof TimeConfiguration) {
UsagePoint usagePoint = (UsagePoint) parent;
if (usagePoint.getLocalTimeParameters() == null) {
usagePoint
.setLocalTimeParameters((TimeConfiguration) resource);
}
}
if (resource instanceof ReadingType) {
MeterReading meterReading = (MeterReading) parent;
if (meterReading.getReadingType() == null) {
meterReading.setReadingType((ReadingType) resource);
}
}
}
}
}
private void linkRelatedCollection(IdentifiedObject resource) {
List<IdentifiedObject> relatedResources = resourceService
.findAllRelated(resource);
for (IdentifiedObject relatedResource : relatedResources) {
// Put the relatedResource in the Transaction
resourceService.merge(relatedResource);
if (resource instanceof UsagePoint) {
if (relatedResource instanceof TimeConfiguration) {
((UsagePoint) resource)
.setLocalTimeParameters((TimeConfiguration) relatedResource);
}
if (relatedResource instanceof MeterReading) {
((UsagePoint) resource)
.addMeterReading((MeterReading) relatedResource);
}
if (relatedResource instanceof ElectricPowerUsageSummary) {
((UsagePoint) resource)
.addElectricPowerUsageSummary((ElectricPowerUsageSummary) relatedResource);
}
if (relatedResource instanceof ElectricPowerQualitySummary) {
((UsagePoint) resource)
.addElectricPowerQualitySummary((ElectricPowerQualitySummary) relatedResource);
}
}
if (resource instanceof MeterReading) {
if (relatedResource instanceof ReadingType) {
((MeterReading) resource)
.setReadingType((ReadingType) relatedResource);
}
if (relatedResource instanceof IntervalBlock) {
((MeterReading) resource)
.addIntervalBlock((IntervalBlock) relatedResource);
}
}
}
}
public void setResourceService(ResourceService resourceService) {
this.resourceService = resourceService;
}
public ResourceService getResourceService(ResourceService resourceService) {
return resourceService;
}
}