/** * Copyright 2012 Universitat Pompeu Fabra. * * 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.onexus.collection.manager.internal; import org.onexus.collection.api.Collection; import org.onexus.collection.api.ICollectionLoader; import org.onexus.collection.api.ICollectionManager; import org.onexus.collection.api.ICollectionStore; import org.onexus.collection.api.IEntityTable; import org.onexus.collection.api.query.Query; import org.onexus.collection.api.utils.FieldLink; import org.onexus.collection.api.utils.LinkUtils; import org.onexus.resource.api.Folder; import org.onexus.resource.api.IProgressManager; import org.onexus.resource.api.IResourceManager; import org.onexus.resource.api.Loader; import org.onexus.resource.api.ORI; import org.onexus.resource.api.Plugin; import org.onexus.resource.api.Progress; import org.onexus.resource.api.Project; import org.onexus.resource.api.Resource; import org.onexus.resource.api.session.LoginContext; import org.onexus.resource.api.utils.ResourceListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class CollectionManager implements ICollectionManager { private static final Logger LOGGER = LoggerFactory.getLogger(CollectionManager.class); private IResourceManager resourceManager; private ICollectionStore collectionStore; private IProgressManager progressManager; private int maxThreads = 4; private ExecutorService executorService; private Map<String, Progress> runningTasks; private Map<String, Progress> runningCollections; public CollectionManager() { super(); this.runningTasks = Collections.synchronizedMap(new HashMap<String, Progress>()); this.runningCollections = Collections.synchronizedMap(new HashMap<String, Progress>()); this.executorService = Executors.newFixedThreadPool(maxThreads); } public void init() { resourceManager.addResourceListener(new ResourceListener() { @Override public void onProjectDelete(Project project) { try { LoginContext.set(LoginContext.SERVICE_CONTEXT, null); // Unload all the collections unloadCollections(project.getORI()); } finally { LoginContext.set(LoginContext.ANONYMOUS_CONTEXT, null); } } @Override public void onResourceDelete(Resource resource) { if (resource instanceof Collection) { unload(resource.getORI()); } } }); } /** * Unload recursively all the collections inside the given ORI. * * @param container The ORI url of the root container */ private void unloadCollections(ORI container) { List<Collection> collections = resourceManager.loadChildren(Collection.class, container); for (Collection collection : collections) { unload(collection.getORI()); } List<Folder> folders = resourceManager.loadChildren(Folder.class, container); for (Folder folder : folders) { unloadCollections(folder.getORI()); } } @Override public boolean isLinkable(Query query, ORI collectionUri) { Collection joinCollection = resourceManager.load(Collection.class, collectionUri); for (Map.Entry<String, ORI> tpDefine : query.getDefine().entrySet()) { ORI tpCollectionUri = tpDefine.getValue().toAbsolute(query.getOn()); Collection tpJoinCollection = resourceManager.load(Collection.class, tpCollectionUri); if (joinCollection.equals(tpJoinCollection)) { return true; } List<FieldLink> links = LinkUtils.getLinkFields(query.getOn(), joinCollection, tpJoinCollection); if (links != null && !links.isEmpty()) { return true; } } return false; } @Override public IEntityTable load(Query query) { LOGGER.debug("Loading query {}", query); Set<ORI> notRegisteredCollections = new HashSet<ORI>(); for (ORI collectionURI : getQueryCollections(query)) { if (!collectionStore.isRegistered(collectionURI)) { notRegisteredCollections.add(collectionURI); } } String taskId = Integer.toHexString(query.hashCode()); Progress progress = getTask(taskId); if (progress == null && !notRegisteredCollections.isEmpty()) { progress = new Progress(taskId, "Loading collections"); LOGGER.info("Starting task {}", taskId); for (ORI collectionURI : notRegisteredCollections) { Project project = resourceManager.getProject(collectionURI.getProjectUrl()); Collection collection = resourceManager.load(Collection.class, collectionURI); if (collection == null) { progress.error("Unknown collection '" + collectionURI + "'"); progress.fail(); } else { String subTaskId = Integer.toHexString(collectionURI.hashCode()); if (!runningCollections.containsKey(subTaskId)) { Progress subProgress = new Progress(subTaskId, "Load '" + collectionURI.getPath() + "'"); progressManager.addProgress(subProgress); runningCollections.put(subTaskId, subProgress); LOGGER.info("Registering {}", collectionURI); collectionStore.register(collectionURI); LOGGER.info("Submiting store collection '{}'", collectionURI); Loader loader = collection.getLoader(); Plugin plugin = project.getPlugin(loader.getPlugin()); ICollectionLoader collectionLoader = resourceManager.getLoader(ICollectionLoader.class, plugin, loader); Runnable command = new InsertCollectionRunnable(LoginContext.get(), runningCollections, plugin, collection, collectionLoader, collectionStore); executorService.submit(command); } progress.addSubTask(runningCollections.get(subTaskId)); } } } IEntityTable partialResults = collectionStore.load(query); if (progress != null) { partialResults = new ProgressEntityTable(progress, partialResults); } return partialResults; } private Set<ORI> getQueryCollections(Query query) { Set<ORI> queryCollections = new HashSet<ORI>(); ORI onUri = query.getOn(); for (ORI collectionUri : query.getDefine().values()) { queryCollections.add(collectionUri.toAbsolute(onUri)); } return queryCollections; } public Progress getTask(String taskId) { Progress progress = runningTasks.get(taskId); if (progress == null) { return null; } if (progress.isDone()) { runningTasks.remove(taskId); } return progress; } @Override public void unload(ORI collectionURI) { if (collectionStore.isRegistered(collectionURI)) { collectionStore.deregister(collectionURI); } } public int getMaxThreads() { return maxThreads; } public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; } public IResourceManager getResourceManager() { return resourceManager; } public void setResourceManager(IResourceManager resourceManager) { this.resourceManager = resourceManager; } public ICollectionStore getCollectionStore() { return collectionStore; } public void setCollectionStore(ICollectionStore collectionStore) { this.collectionStore = collectionStore; } @Override public String getMount() { return "oql"; } public IProgressManager getProgressManager() { return progressManager; } public void setProgressManager(IProgressManager progressManager) { this.progressManager = progressManager; } }