/*******************************************************************************
* Copyright (c) 2008-2011 Chair for Applied Software Engineering,
* Technische Universitaet Muenchen.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
******************************************************************************/
package org.eclipse.emf.emfstore.server.taskmanager.tasks;
import java.util.Date;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.emfstore.common.model.Project;
import org.eclipse.emf.emfstore.common.model.util.ModelUtil;
import org.eclipse.emf.emfstore.server.core.MonitorProvider;
import org.eclipse.emf.emfstore.server.model.ProjectHistory;
import org.eclipse.emf.emfstore.server.model.versioning.ChangePackage;
import org.eclipse.emf.emfstore.server.model.versioning.Version;
import org.eclipse.emf.emfstore.server.taskmanager.Task;
/**
* This task is used to clean the memory by proxifying the projectstates.
*
* @author wesendon
*/
public class CleanMemoryTask extends Task {
private static final long PERIOD = 60 * 1000;
private static final boolean LOG_UNLOADING = false;
// private final ServerSpace serverSpace;
private final ResourceSet resourceSet;
/**
* Default constructor.
*
* @param resourceSet
* the {@link ResourceSet} that should be considered for unloading
*
*/
public CleanMemoryTask(ResourceSet resourceSet) {
super(new Date(System.currentTimeMillis() + PERIOD), PERIOD);
// this.serverSpace = serverSpace;
this.resourceSet = resourceSet;
}
/**
* {@inheritDoc}
*/
@Override
public void executeTask() {
synchronized (MonitorProvider.getInstance().getMonitor()) {
boolean unloadedSomething = false;
// LOGGER.info("checking whether projectstates have to be unloaded.");
// ResourceSet resourceSet =
// serverSpace.eResource().getResourceSet();
EList<Resource> resources = resourceSet.getResources();
for (int i = 0; i < resources.size(); i++) {
Resource res = resources.get(i);
if (res.isLoaded()) {
// unload projecstates except current
Project project = getElement(res, Project.class);
if (project != null) {
Version version = getParent(project, Version.class);
if (version != null && version.getNextVersion() != null) {
log("unloading: " + project);
unload(res);
unloadedSomething = true;
}
}
// unload changepackages except last 25
int keep = 25;
ChangePackage cp = getElement(res, ChangePackage.class);
if (cp != null) {
Version version = getParent(cp, Version.class);
ProjectHistory history = getParent(version, ProjectHistory.class);
if (version != null && history != null
&& version.getPrimarySpec().getIdentifier() > (history.getVersions().size() - keep)) {
log("unloading: " + cp);
unload(res);
unloadedSomething = true;
}
}
}
}
if (unloadedSomething) {
System.gc();
}
}
}
private void log(String str) {
if (LOG_UNLOADING) {
ModelUtil.logInfo(str);
}
}
@SuppressWarnings("unchecked")
private <T> T getElement(Resource res, Class<T> clazz) {
if (res.getContents().size() == 1 && clazz.isInstance(res.getContents().get(0))) {
return (T) res.getContents().get(0);
}
return null;
}
@SuppressWarnings("unchecked")
private <T> T getParent(EObject obj, Class<T> clazz) {
if (obj != null && obj.eContainer() != null && clazz.isInstance(obj.eContainer())) {
return (T) obj.eContainer();
}
return null;
}
private void unload(Resource res) {
// sanity check: this check is specific to our 1 element per resource
// structure for projects and changepackages
if (res.getContents().size() != 1) {
return;
}
EObject eObject = res.getContents().get(0);
// unload to proxify
res.unload();
// sanity check
if (!eObject.eIsProxy()) {
ModelUtil.logWarning("Couldn't unload: " + eObject);
return;
}
// unset all contained childs.
for (EReference child : eObject.eClass().getEAllContainments()) {
eObject.eUnset(child);
}
}
}