package org.jtheque.resources.impl; import org.jtheque.core.Folders; import org.jtheque.core.utils.WebHelper; import org.jtheque.resources.Resource; import org.jtheque.resources.ResourceService; import org.jtheque.states.StateService; import org.jtheque.utils.annotations.GuardedInternally; import org.jtheque.utils.annotations.ThreadSafe; import org.jtheque.utils.bean.Version; import org.jtheque.utils.collections.CollectionUtils; import org.jtheque.utils.io.FileException; import org.jtheque.utils.io.WebUtils; import org.jtheque.utils.ui.SwingUtils; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.slf4j.LoggerFactory; import org.springframework.osgi.context.BundleContextAware; import java.io.File; import java.util.Collection; import java.util.List; import java.util.Map; /* * Copyright JTheque (Baptiste Wicht) * * 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. */ /** * A resource service implementation. * * @author Baptiste Wicht */ @ThreadSafe public final class ResourceServiceImpl implements ResourceService, BundleContextAware { @GuardedInternally private final Map<String, ResourceDescriptor> descriptorCache = CollectionUtils.newConcurrentMap(5); @GuardedInternally private final Map<String, Bundle> installedBundles = CollectionUtils.newConcurrentMap(20); @GuardedInternally private final ResourceState resourceState; @javax.annotation.Resource private WebHelper webHelper; private BundleContext bundleContext; /** * Construct a new Resource Service. * * @param stateService The state service. */ public ResourceServiceImpl(StateService stateService) { super(); resourceState = stateService.getState(new ResourceState()); } @Override public void addResource(Resource resource) { resourceState.addResource(resource); } @Override public Collection<Resource> getResources() { return CollectionUtils.protect(resourceState.getResourceSets()); } @Override public List<Version> getVersions(String id) { List<Version> versions = CollectionUtils.newList(3); for (Resource resource : resourceState.getResourceSets()) { if (resource.getId().equals(id)) { versions.add(resource.getVersion()); } } return versions; } @Override public boolean exists(String id) { for (Resource resource : resourceState.getResourceSets()) { if (resource.getId().equals(id)) { return true; } } return false; } @Override public Resource getResource(String id, Version version) { for (Resource resource : resourceState.getResourceSets()) { if (resource.getId().equals(id) && resource.getVersion().equals(version)) { return resource; } } return null; } @Override public Resource getOrDownloadResource(String id, Version version, String url) { Resource resource = getResource(id, version); if (resource == null) { LoggerFactory.getLogger(getClass()).debug("Resource {} not installed, download it at URL {}", id, url); resource = downloadResource(url, version); resourceState.addResource(resource); } return resource; } /** * Download the given resource. * * @param url The URL of the resource descriptor. * @param version The version to download. * * @return The downloaded resource. */ private Resource downloadResource(String url, Version version) { SwingUtils.assertNotEDT("downloadResource(String, Version)"); if (webHelper.isReachable(url)) { if (!descriptorCache.containsKey(url)) { descriptorCache.put(url, ResourceDescriptorReader.readResourceDescriptor(url)); } ResourceDescriptor descriptor = descriptorCache.get(url); if (descriptor == null) { return null; } Resource cachedResource = getResource(descriptor.getId(), version); if (cachedResource != null) { return cachedResource; } for (ResourceVersion resourceVersion : descriptor.getVersions()) { if (resourceVersion.getVersion().equals(version)) { return downloadResource(descriptor, resourceVersion); } } } return null; } /** * Download the given resource. * * @param descriptor The descriptor of the resource. * @param resourceVersion The version to download from. * * @return The downloaded resource. */ private static Resource downloadResource(AbstractDescriptor descriptor, ResourceVersion resourceVersion) { File resourceFolder = getResourceFolder(descriptor.getId(), resourceVersion.getVersion()); downloadFile(resourceFolder, resourceVersion.getFile(), resourceVersion.getUrl()); return new ResourceImpl( descriptor.getId(), resourceVersion.getVersion(), resourceVersion.getUrl(), resourceVersion.getFile(), resourceVersion.isLibrary()); } /** * Download the file. * * @param resourceFolder The resource folder. * @param fileName The name of the file. * @param url The URL of the file. */ private static void downloadFile(File resourceFolder, String fileName, String url) { File filePath = new File(resourceFolder, fileName); try { WebUtils.downloadFile(url, filePath.getAbsolutePath()); } catch (FileException e) { LoggerFactory.getLogger(ResourceServiceImpl.class).error(e.getMessage(), e); } } @Override public void installResource(Resource resource) { SwingUtils.assertNotEDT("installResource(Resource)"); if (resource.isLibrary() && !installedBundles.containsKey(resource.getId())) { try { Bundle bundle = bundleContext.installBundle("file:" + getResourceFolder(resource.getId(), resource.getVersion()).getAbsolutePath() + '/' + resource.getFile()); installedBundles.put(resource.getId(), bundle); } catch (BundleException e) { LoggerFactory.getLogger(getClass()).error(e.getMessage(), e); } } } @Override public boolean isNotInstalled(String id, Version version) { return getResource(id, version) == null; } /** * Return the resource folder for the given resource. * * @param id The id of the resource. * @param version The version of the resource. * * @return The folder of the resource. */ private static File getResourceFolder(String id, Version version) { File file = new File(Folders.getCoreFolder(), "resources/" + id + '/' + version); if (!file.exists() && !file.mkdirs()) { LoggerFactory.getLogger(ResourceServiceImpl.class).error("Unable to create the resource folder {}", file.getAbsolutePath()); } return file; } @Override public void setBundleContext(BundleContext bundleContext) { this.bundleContext = bundleContext; } }