Java tutorial
/* * Copyright (c) 2012 Data Harmonisation Panel * * All rights reserved. This program and the accompanying materials are made * available under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * Data Harmonisation Panel <http://www.dhpanel.eu> */ package eu.esdihumboldt.util.resource.scavenger; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.net.URI; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.apache.commons.io.FileUtils; import org.eclipse.core.runtime.Platform; import org.eclipse.osgi.service.datalocation.Location; import de.cs3d.util.logging.ALogger; import de.cs3d.util.logging.ALoggerFactory; /** * Scans for folder resources in a specific location or references a single * resource. * * @param <T> the resource reference type * @author Simon Templer */ public abstract class AbstractResourceScavenger<T> implements ResourceScavenger<T> { /** * Resource identifier in one resource mode. */ public static final String DEFAULT_RESOURCE_ID = "resource"; private static final ALogger log = ALoggerFactory.getLogger(AbstractResourceScavenger.class); private final File huntingGrounds; private final Map<String, T> resources = new HashMap<>(); private final Set<String> reserved = new HashSet<>(); /** * Create a scavenger instance. Subclass constructors should call * {@link #triggerScan()} after to initialize the scavenger. * * @param scavengeLocation the location to scan, if the location does not * exist or is not accessible, a default location inside the * platform instance location is used * @param instanceLocPath the instance location sub-path to use if the * scavengeLocation is invalid or <code>null</code>, may be * <code>null</code> if the platform instance location should not * be used as fall-back */ public AbstractResourceScavenger(File scavengeLocation, String instanceLocPath) { if (scavengeLocation == null || !scavengeLocation.exists() && instanceLocPath != null) { // use default location Location location = Platform.getInstanceLocation(); if (location != null) { try { File instanceLoc = new File(URI.create(location.getURL().toString().replaceAll(" ", "%20"))); scavengeLocation = new File(instanceLoc, instanceLocPath); if (!scavengeLocation.exists()) { scavengeLocation.mkdirs(); } } catch (Exception e) { log.error("Unable to determine instance location, can't initialize resource scavenger.", e); scavengeLocation = null; } huntingGrounds = scavengeLocation; } else { log.error("No instance location, can't initialize resource scavenger."); huntingGrounds = null; } } else { huntingGrounds = scavengeLocation; } if (huntingGrounds != null) { log.info("Resources location is " + huntingGrounds.getAbsolutePath()); } // triggerScan(); } /** * @see ResourceScavenger#triggerScan() */ @Override public void triggerScan() { synchronized (resources) { if (huntingGrounds != null) { if (huntingGrounds.isDirectory()) { // scan for sub-directories Set<String> foundIds = new HashSet<String>(); File[] resourceDirs = huntingGrounds.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { // accept non-hidden directories return pathname.isDirectory() && !pathname.isHidden(); } }); for (File resourceDir : resourceDirs) { String resourceId = resourceDir.getName(); foundIds.add(resourceId); if (!resources.containsKey(resourceId)) { // resource reference not loaded yet T handler; try { handler = loadReference(resourceDir, null, resourceId); resources.put(resourceId, handler); } catch (IOException e) { log.error("Error creating resource reference", e); } } else { // update existing resource updateResource(resources.get(resourceId), resourceId); } } Set<String> removed = new HashSet<String>(resources.keySet()); removed.removeAll(foundIds); // deal with resources that have been removed for (String resourceId : removed) { T reference = resources.remove(resourceId); if (reference != null) { // remove active environment onRemove(reference, resourceId); } } } else { // one project mode if (!resources.containsKey(DEFAULT_RESOURCE_ID)) { // project configuration not loaded yet T handler; try { handler = loadReference(huntingGrounds.getParentFile(), huntingGrounds.getName(), DEFAULT_RESOURCE_ID); resources.put(DEFAULT_RESOURCE_ID, handler); } catch (IOException e) { log.error("Error creating project handler", e); } } else { // update existing project updateResource(resources.get(DEFAULT_RESOURCE_ID), DEFAULT_RESOURCE_ID); } } } } } /** * Called when a resource has been removed. * * @param reference the resource reference * @param resourceId the resource identifier */ protected abstract void onRemove(T reference, String resourceId); /** * Called when a resource has been added or changed. * * @param reference the resource reference to update * @param resourceId the resource identifier */ protected abstract void updateResource(T reference, String resourceId); /** * Load a resource reference. * * @param resourceFolder the resource folder * @param resourceFileName the name of the resource file in that folder, may * be <code>null</code> if unknown * @param resourceId the resource identifier * @return the resource reference * @throws IOException if the resource cannot be accessed or loaded */ protected abstract T loadReference(File resourceFolder, String resourceFileName, String resourceId) throws IOException; @Override public File reserveResourceId(String resourceId) throws ScavengerException { if (!allowAddResource()) { throw new ScavengerException("Adding a resource not allowed."); } // trigger a scan to be up-to-date triggerScan(); // TODO check if resourceId is valid synchronized (resources) { if (resources.containsKey(resourceId)) { // there already is a project with that ID throw new ScavengerException("Project ID already taken."); } if (reserved.contains(resourceId)) { // the project ID is already reserved throw new ScavengerException("Project ID already reserved."); } reserved.add(resourceId); File projectFolder = new File(huntingGrounds, resourceId); if (!projectFolder.exists()) { // try creating the directory try { projectFolder.mkdir(); } catch (Exception e) { throw new ScavengerException("Could not create project directory", e); } } if (!projectFolder.exists()) { throw new ScavengerException("Could not create project directory"); } return projectFolder; } } /** * @see ResourceScavenger#releaseResourceId(String) */ @Override public void releaseResourceId(String resourceId) { if (!allowAddResource()) { return; } synchronized (resources) { if (reserved.contains(resourceId)) { reserved.remove(resourceId); // delete directoy try { FileUtils.deleteDirectory(new File(huntingGrounds, resourceId)); } catch (IOException e) { log.error("Error deleting resource directory content", e); } } } } @Override public boolean allowAddResource() { return huntingGrounds.isDirectory(); } @Override public Set<String> getResources() { synchronized (resources) { return new TreeSet<String>(resources.keySet()); } } @Override public T getReference(String resourceId) { return resources.get(resourceId); } }