com.jaspersoft.jasperserver.api.engine.jasperreports.service.impl.StandardDataSnapshotService.java Source code

Java tutorial

Introduction

Here is the source code for com.jaspersoft.jasperserver.api.engine.jasperreports.service.impl.StandardDataSnapshotService.java

Source

/*
 * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com.
 *
 * Unless you have purchased  a commercial license agreement from Jaspersoft,
 * the following license terms  apply:
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License  as
 * published by the Free Software Foundation, either version 3 of  the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero  General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public  License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.jaspersoft.jasperserver.api.engine.jasperreports.service.impl;

import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import net.sf.jasperreports.data.cache.DataSnapshot;
import net.sf.jasperreports.engine.ReportContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.jaspersoft.jasperserver.api.JSException;
import com.jaspersoft.jasperserver.api.common.domain.ExecutionContext;
import com.jaspersoft.jasperserver.api.engine.jasperreports.service.DataCacheProvider;
import com.jaspersoft.jasperserver.api.engine.jasperreports.service.DataCacheProvider.SnapshotSaveStatus;
import com.jaspersoft.jasperserver.api.engine.jasperreports.service.DataSnapshotCachingService;
import com.jaspersoft.jasperserver.api.engine.jasperreports.service.DataSnapshotPersistResult;
import com.jaspersoft.jasperserver.api.engine.jasperreports.service.DataSnapshotService;
import com.jaspersoft.jasperserver.api.engine.jasperreports.util.DefaultDataCacheSnapshot;
import com.jaspersoft.jasperserver.api.metadata.common.domain.ResourceLookup;
import com.jaspersoft.jasperserver.api.metadata.common.service.RepositoryService;
import com.jaspersoft.jasperserver.api.metadata.common.service.impl.hibernate.util.RepositoryUtils;
import com.jaspersoft.jasperserver.api.metadata.data.cache.DataCacheSnapshot;
import com.jaspersoft.jasperserver.api.metadata.data.cache.DataCacheSnapshotData;
import com.jaspersoft.jasperserver.api.metadata.data.cache.DataCacheSnapshotMetadata;
import com.jaspersoft.jasperserver.api.metadata.data.cache.DataSnapshotPersistenceService;
import com.jaspersoft.jasperserver.api.metadata.data.cache.DataSnapshotPersistentMetadata;
import com.jaspersoft.jasperserver.api.metadata.data.cache.DataSnapshotSavedId;
import com.jaspersoft.jasperserver.api.metadata.jasperreports.domain.ReportUnit;
import com.jaspersoft.jasperserver.api.metadata.view.domain.FilterCriteria;

/**
 * @author Lucian Chirita (lucianc@users.sourceforge.net)
 * @version $Id: StandardDataSnapshotService.java 47331 2014-07-18 09:13:06Z kklein $
 */
public class StandardDataSnapshotService implements DataSnapshotService {

    private static final Log log = LogFactory.getLog(StandardDataSnapshotService.class);

    private boolean snapshotRecordingEnabled;
    private boolean snapshotPersistenceEnabled;

    private DataSnapshotPersistenceService persistenceService;
    private DataSnapshotCachingService cachingService;
    private DataCacheProvider dataCacheProvider;
    private RepositoryService repository;
    private RepositoryService unsecureRepository;

    public DataSnapshotPersistentMetadata getSnapshotMetadata(ExecutionContext context, long snapshotId) {
        // look in the cache for the metadata
        DataSnapshotPersistentMetadata metadata = cachingService.getSnapshotMetadata(context, snapshotId);
        if (metadata == null) {
            if (log.isDebugEnabled()) {
                log.debug("no cached snapshot " + snapshotId);
            }
        } else {
            // verify the version with the latest persistent version
            int cachedVersion = metadata.getVersion();
            if (persistenceService.matchesVersion(context, snapshotId, cachedVersion)) {
                if (log.isDebugEnabled()) {
                    log.debug("found cached snapshot " + snapshotId + " at version " + cachedVersion);
                }
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("invalidating cached snapshot " + snapshotId + " with version " + cachedVersion);
                }

                // purge the old entry from the cache
                cachingService.invalidateSnapshot(context, snapshotId);
                metadata = null;
            }
        }

        if (metadata == null) {
            if (log.isDebugEnabled()) {
                log.debug("loading data snapshot metadata " + snapshotId);
            }

            // load from the persistent storage
            metadata = persistenceService.loadDataSnapshotMetadata(context, snapshotId);

            if (metadata == null) {
                // this shouldn't normally happen, but treating as a non blocking error
                log.info("saved data snapshot metadata " + snapshotId + " not found");
                return null;
            }

            if (log.isDebugEnabled()) {
                log.debug("loaded snapshot metadata " + snapshotId + " at version " + metadata.getVersion());
            }

            // put it in the cache
            cachingService.putSnapshotMetadata(context, snapshotId, metadata);
        }

        return metadata;
    }

    public DataSnapshot getSnapshotContents(ExecutionContext context, long contentsId) {
        DataSnapshot snapshotContents = cachingService.getSnapshotContents(context, contentsId);
        if (snapshotContents == null) {
            if (log.isDebugEnabled()) {
                log.debug("loading data snapshot contents " + contentsId);
            }

            snapshotContents = persistenceService.loadDataSnapshot(context, contentsId);

            if (snapshotContents == null) {
                // this shouldn't normally happen, but treating as a non blocking error
                log.info("saved data snapshot contents " + contentsId + " not found");
                return null;
            }

            if (log.isDebugEnabled()) {
                log.debug("loaded data snapshot contents " + contentsId);
            }

            cachingService.putSnapshotContents(context, contentsId, snapshotContents);
        } else {
            if (log.isDebugEnabled()) {
                log.debug("found cached snapshot contents " + contentsId);
            }
        }
        return snapshotContents;
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
    public long saveDataSnapshot(ExecutionContext context, DataCacheSnapshot snapshot, Long existingSnapshotId) {
        // saving
        DataSnapshotSavedId saved = persistenceService.saveDataSnapshot(context, snapshot, existingSnapshotId);

        // also adding to the cache
        cachingService.put(context, saved, snapshot);

        return saved.getSnapshotId();
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
    public void deleteSnapshot(ExecutionContext context, long snapshotId) {
        persistenceService.deleteSnapshot(snapshotId);

        // remove from the cache
        cachingService.invalidateSnapshot(context, snapshotId);
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
    @Override
    public boolean saveAutoReportDataSnapshot(ExecutionContext context, ReportContext reportContext,
            ReportUnit reportUnit) {
        // this method should only be called for initial data snapshots saves, not updates
        DataCacheProvider.SnapshotSaveStatus saveStatus = dataCacheProvider.getSnapshotSaveStatus(reportContext);
        if (saveStatus != DataCacheProvider.SnapshotSaveStatus.NEW) {
            throw new JSException("Data snapshot is not new");
        }

        ReportUnit repositoryRU = loadRepositoryReportUnit(context, reportUnit);
        boolean dirtyReportUnit = applyReportUnitChanges(context, reportContext, repositoryRU, false,
                reportUnit.getURIString());

        if (!dirtyReportUnit) {
            // nothing to save in the report unit
            return false;
        }

        if (log.isDebugEnabled()) {
            log.debug("saving report unit " + repositoryRU.getPath());
        }

        getUnsecureRepository().saveResource(context, repositoryRU);
        return true;
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
    @Override
    public boolean saveReportDataSnapshot(ExecutionContext context, ReportContext reportContext,
            ReportUnit reportUnit) {
        ReportUnit repositoryRU = loadRepositoryReportUnit(context, reportUnit);
        boolean dirtyReportUnit = applyReportUnitChanges(context, reportContext, repositoryRU, false,
                reportUnit.getURIString());

        if (!dirtyReportUnit) {
            // nothing to save in the report unit
            return false;
        }

        if (log.isDebugEnabled()) {
            log.debug("saving report unit " + repositoryRU.getPath());
        }

        getRepository().saveResource(context, repositoryRU);
        return true;
    }

    protected boolean applyReportUnitChanges(ExecutionContext context, ReportContext reportContext,
            ReportUnit reportUnit, boolean copyDataSnapshot, String originalReportUri) {
        boolean dirtyReportUnit = false;

        Long currentSnapshotId = reportUnit.getDataSnapshotId();
        Long existingSnapshotId = copyDataSnapshot ? null : reportUnit.getDataSnapshotId();
        DataSnapshotPersistResult result = persistDataSnapshot(context, reportContext, existingSnapshotId);
        Long savedSnapshotId = result.getSavedSnapshotId();
        if (currentSnapshotId == null ? savedSnapshotId != null
                : (savedSnapshotId == null || !currentSnapshotId.equals(savedSnapshotId))) {
            // data snapshot Id has changed
            reportUnit.setDataSnapshotId(savedSnapshotId);
            dirtyReportUnit = true;
        }

        return dirtyReportUnit;
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
    @Override
    public DataSnapshotPersistResult persistDataSnapshot(ExecutionContext context, ReportContext reportContext,
            Long existingSnapshotId) {
        // if not copying, only saving data snapshot when it has modified
        DataCacheSnapshot snapshot = dataCacheProvider.getDataSnapshot(context, reportContext);

        if (!isSnapshotPersistenceEnabled() || (snapshot != null && !snapshot.getSnapshot().isPersistable())) {
            if (log.isDebugEnabled()) {
                log.debug("data snapshot not persistable");
            }
            // do not save anything
            snapshot = null;
        }

        boolean changed;
        Long savedSnapshotId;
        if (snapshot == null) {
            if (log.isDebugEnabled()) {
                log.debug("no data snapshot to save");
            }

            savedSnapshotId = null;

            if (existingSnapshotId == null) {
                changed = false;
            } else {
                // deleting current snapshot
                if (log.isDebugEnabled()) {
                    log.debug("deleting data snapshot " + existingSnapshotId);
                }

                deleteSnapshot(context, existingSnapshotId);
                changed = true;
            }
        } else {
            if (snapshot.isSaved() && existingSnapshotId != null) {
                // the snapshot didn't change, nothing to save
                if (log.isDebugEnabled()) {
                    log.debug("snapshot " + existingSnapshotId + " has not changed");
                }

                savedSnapshotId = existingSnapshotId;
                changed = false;
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("saving data snapshot with current id " + existingSnapshotId);
                }

                savedSnapshotId = saveDataSnapshot(context, snapshot, existingSnapshotId);
                changed = true;

                dataCacheProvider.snapshotSaved(context, reportContext, snapshot, savedSnapshotId);

                if (log.isDebugEnabled()) {
                    log.debug("saved data snapshot " + savedSnapshotId);
                }
            }
        }

        return new DataSnapshotPersistResult(changed, savedSnapshotId);
    }

    protected ReportUnit loadRepositoryReportUnit(ExecutionContext context, ReportUnit reportUnit) {
        // reload the report unit because the view report flow modifies it
        ReportUnit repositoryRU = (ReportUnit) getRepository().getResource(context, reportUnit.getURIString(),
                ReportUnit.class);
        if (repositoryRU == null) {
            throw new JSException("Report unit not found at " + reportUnit.getURIString());
        }

        // check if the report got modified since loading
        if (repositoryRU.getVersion() != reportUnit.getVersion()) {
            throw new JSException("Report unit has been modified after it was loaded");
        }
        return repositoryRU;
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
    @Override
    public String saveReportDataSnapshotCopy(ExecutionContext context, ReportContext reportContext,
            ReportUnit reportUnit, String folderUri, String label, boolean overwrite)
            throws CopyDestinationExistsException {
        String copyName = makeResourceName(label);
        String copyURI = RepositoryUtils.concatenatePath(folderUri, copyName);

        // fetching as ResourceLookup so that we don't fully load the resource
        FilterCriteria criteria = FilterCriteria.createFilter();
        criteria.addFilterElement(FilterCriteria.createResourceURIFilter(copyURI));
        List<ResourceLookup> resources = getRepository().loadResourcesList(context, criteria);
        if (resources != null && !resources.isEmpty()) {
            ResourceLookup resource = resources.get(0);
            // first check that the target is a report unit
            if (!ReportUnit.class.getName().equals(resource.getResourceType())) {
                throw new CopyDestinationNotReportException(copyURI);
            }

            if (!overwrite) {
                throw new CopyDestinationExistsException(copyURI);
            }

            if (log.isDebugEnabled()) {
                log.debug("deleting existing resource " + copyURI);
            }
            getRepository().deleteResource(context, copyURI);
        }

        ReportUnit reportUnitCopy = getRepository().makeResourceCopy(context, reportUnit.getURIString(),
                reportUnit.getVersion(), ReportUnit.class, copyURI);

        if (reportUnitCopy == null) {
            throw new JSException("Report unit not found at " + reportUnit.getURIString());
        }

        reportUnitCopy.setLabel(label);

        applyReportUnitChanges(context, reportContext, reportUnitCopy, true, reportUnit.getURIString());

        if (log.isDebugEnabled()) {
            log.debug("saving report unit copy of " + reportUnit.getURIString() + " at " + copyURI);
        }

        getRepository().saveResource(context, reportUnitCopy);
        return copyURI;
    }

    protected static final Pattern PATTERN_RESOURCE_NAME_REPLACE = Pattern.compile("[^\\p{L}\\p{N}_.-]");

    protected String makeResourceName(String label) {
        return PATTERN_RESOURCE_NAME_REPLACE.matcher(label).replaceAll("_");
    }

    public DataCacheSnapshotData loadSnapshotData(ExecutionContext context, Long snapshotId) {
        // simply delegate
        return persistenceService.loadSnapshotData(context, snapshotId);
    }

    public long saveDataSnapshot(ExecutionContext context, DataCacheSnapshotData dataSnapshot) {
        // simply delegate
        return persistenceService.saveDataSnapshot(context, dataSnapshot);
    }

    public Long copyDataSnapshot(Long snapshotId) {
        // simply delegate
        return persistenceService.copyDataSnapshot(snapshotId);
    }

    public DataSnapshotPersistenceService getPersistenceService() {
        return persistenceService;
    }

    public void setPersistenceService(DataSnapshotPersistenceService persistenceService) {
        this.persistenceService = persistenceService;
    }

    public DataSnapshotCachingService getCachingService() {
        return cachingService;
    }

    public void setCachingService(DataSnapshotCachingService cachingService) {
        this.cachingService = cachingService;
    }

    public DataCacheProvider getDataCacheProvider() {
        return dataCacheProvider;
    }

    public void setDataCacheProvider(DataCacheProvider dataCacheProvider) {
        this.dataCacheProvider = dataCacheProvider;
    }

    public RepositoryService getRepository() {
        return repository;
    }

    public void setRepository(RepositoryService repository) {
        this.repository = repository;
    }

    public RepositoryService getUnsecureRepository() {
        return unsecureRepository;
    }

    public void setUnsecureRepository(RepositoryService unsecureRepository) {
        this.unsecureRepository = unsecureRepository;
    }

    public boolean isSnapshotRecordingEnabled() {
        return snapshotRecordingEnabled;
    }

    public void setSnapshotRecordingEnabled(boolean snapshotRecordingEnabled) {
        this.snapshotRecordingEnabled = snapshotRecordingEnabled;
    }

    public boolean isSnapshotPersistenceEnabled() {
        return snapshotPersistenceEnabled;
    }

    public void setSnapshotPersistenceEnabled(boolean snapshotPersistenceEnabled) {
        this.snapshotPersistenceEnabled = snapshotPersistenceEnabled;
    }

}