/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.foundation.rm;
import java.io.FileNotFoundException;
import java.util.Date;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openflexo.foundation.FlexoException;
/**
* @author sylvain
*
*/
public abstract class FlexoGeneratedResource<GRD extends GeneratedResourceData> extends FlexoFileResource<GRD> {
private static final Logger logger = Logger.getLogger(FlexoGeneratedResource.class.getPackage().getName());
@Override
public abstract ResourceType getResourceType();
/**
* @param builder
*/
public FlexoGeneratedResource(FlexoProjectBuilder builder) {
super(builder);
}
/**
* @param aProject
*/
public FlexoGeneratedResource(FlexoProject aProject) {
super(aProject);
}
private Date _lastGenerationDate;
public Date getLastGenerationDate() {
if (_lastGenerationDate == null || isConnected() && !getFile().exists()) {
_lastGenerationDate = getDiskLastModifiedDate();
}
return _lastGenerationDate;
}
public void setLastGenerationDate(Date aDate) {
_lastGenerationDate = aDate;
}
/**
* This date is VERY IMPORTANT and CRITICAL since this is the date used by ResourceManager to compute dependancies between resources.
* This method returns the date that must be considered as last known update for this resource
*
* The date to be considered for generated resources are typically the date when this resource was generated for the last time.
*
* @return a Date object
*/
@Override
public synchronized Date getLastUpdate() {
return getLastGenerationDate();
}
/**
* Return a flag indicating if resource is loaded in memory
*
* @return
*/
public synchronized boolean isLoaded() {
return _resourceData != null;
}
// Enhance visibility of this method
@Override
public FileWritingLock willWriteOnDisk() {
return super.willWriteOnDisk();
}
// Enhance visibility of this method
@Override
public void hasWrittenOnDisk(FileWritingLock lock) {
super.hasWrittenOnDisk(lock);
}
// Enhance visibility of this method
@Override
public boolean isSaving() {
return super.isSaving();
}
/**
* Calling this ensure that generated resource is up-to-date. If re-genereration was necessary, if is performed. If this case, return
* true
*
* @return a boolean indicating if regeneration was necessary
*/
public boolean ensureGenerationIsUpToDate() throws FlexoException {
FlexoResourceTree tree;
try {
tree = update();
return !tree.isEmpty();
} catch (ResourceDependencyLoopException e) {
if (logger.isLoggable(Level.SEVERE)) {
logger.log(Level.SEVERE, "Loop in dependant resources of " + this + "!", e);
}
throw new FlexoException("Loop in dependant resources of " + this + "!", e);
} catch (FileNotFoundException e) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, "File not found exception.", e);
}
e.printStackTrace();
}
return false;
}
public boolean needsGeneration() {
if (!getFile().exists()) {
return true;
}
try {
return needsUpdate();
} catch (ResourceDependencyLoopException e) {
// Warns about the exception
if (logger.isLoggable(Level.SEVERE)) {
logger.log(Level.SEVERE, "Loop in dependant resources of " + this + "!", e);
}
return false;
}
}
@Override
protected void performUpdating(FlexoResourceTree updatedResources) throws ResourceDependencyLoopException, FlexoException,
FileNotFoundException {
// This is a little hack for resource that depends of nothing (which is wrong!!! a generated resource should always depend of
// something)
if (updatedResources.isEmpty() && !getFile().exists()) {
if (!getDependentResources().isEmpty()) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("This is not normal, the generated file (" + getFileName()
+ ") does not exist but RM has not computed that it must be generated");
}
}
generate();
}
if (!updatedResources.isEmpty()) {
for (Enumeration<FlexoResource<FlexoResourceData>> e = getDependentResources().elements(false,
getProject().getDependancyScheme()); e.hasMoreElements();) {
FlexoResource<FlexoResourceData> resource = e.nextElement();
resource.update();
}
generate();
} else {
getGeneratedResourceData();
}
}
/**
* Calling this assume that when returning, generated resource will be up-to-date. Regenerate or not depending on dependancies computing
*
* @param requestingResources
* @return true is generation was required
*/
/*
* public boolean ensureGenerationIsUpToDate(Vector requestingResources) {
* try { logger.info("Checking dependancies"); Vector updatedResources =
* checkDependancies(requestingResources); logger.info("Found
* "+updatedResources.size()+" resources for which last update is more
* recent than last generated date which is "+(new SimpleDateFormat("dd/MM
* HH:mm:ss")).format(getLastGenerationDate())); if
* ((updatedResources.size() > 0) || (!getFile().exists())) { // If either
* some dependant resources required to be synchronized // OR if file was
* never generated, generate it logger.info("Generate...."); generate();
* logger.info("Generate....DONE"); return true; } else { logger.info("No
* regeneration required"); } } catch (LoadResourceException e) {
* logger.warning ("Could not load resource: "+e.getClass().getName()+". See
* console for details."); e.printStackTrace();
* e.getCause().printStackTrace(); } catch (SaveResourceException e) { //
* Warns about the exception logger.warning ("Could not save generated data:
* "+e.getClass().getName()+". See console for details.");
* e.printStackTrace(); } return false; }
*/
public final void generate() throws SaveResourceException, FlexoException {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Generate " + getName());
}
_resourceData = doGenerate();
FileWritingLock lock = willWriteOnDisk();
_resourceData.writeToFile(getFile());
hasWrittenOnDisk(lock);
finalizeGeneration();
setLastGenerationDate(new Date());
notifyResourceChanged();
notifyResourceStatusChanged();
if (logger.isLoggable(Level.FINE)) {
logger.fine("Generate....DONE");
}
}
/**
* This method is intended to be overidden by sub-classes that need to free resources and data.
*
*/
public void finalizeGeneration() {
}
public GRD getGeneratedResourceData() {
if (_resourceData != null) {
return _resourceData;
} else {
if (isGeneratedResourceDataReadable()) {
try {
_resourceData = readGeneratedResourceData();
} catch (FlexoException e) {
e.printStackTrace();
}
}
return _resourceData;
}
}
protected GRD doGenerate() throws FlexoException {
if (getGeneratedResourceData() != null) {
getGeneratedResourceData().regenerate();
return getGeneratedResourceData();
} else {
GRD returned = createGeneratedResourceData();
returned.generate();
return returned;
}
}
public void resetGeneratedResourceData() {
_resourceData = null;
}
protected abstract GRD createGeneratedResourceData();
public abstract boolean isGeneratedResourceDataReadable();
public abstract GRD readGeneratedResourceData() throws FlexoException;
@Override
protected final Date getRequestDateToBeUsedForOptimisticDependencyChecking(FlexoResource resource) {
return getLastUpdate();
}
}