/* * #! * Ontopia Engine * #- * Copyright (C) 2001 - 2013 The Ontopia Project * #- * 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 net.ontopia.topicmaps.entry; import java.io.File; import java.io.IOException; import java.net.URL; import java.net.MalformedURLException; import net.ontopia.infoset.core.LocatorIF; import net.ontopia.infoset.impl.basic.URILocator; import net.ontopia.topicmaps.core.StoreDeletedException; import net.ontopia.topicmaps.core.TopicMapIF; import net.ontopia.topicmaps.core.TopicMapStoreIF; import net.ontopia.topicmaps.core.events.TopicMapListenerIF; import net.ontopia.topicmaps.impl.utils.AbstractTopicMapStore; import net.ontopia.utils.OntopiaRuntimeException; /** * INTERNAL: An abstract topic map reference class that retrieves * topic maps referenced through URLs. Subclasses should implement the * loadTopicMap method.<p> * * @since 1.3.2 */ public abstract class AbstractURLTopicMapReference extends AbstractTopicMapReference { protected URL url; protected LocatorIF base_address; protected boolean duplicate_suppression; protected boolean reuse_store = true; protected TopicMapStoreIF store; protected boolean maintainFulltextIndexes; protected String indexDirectory; public AbstractURLTopicMapReference(String id, String title, URL url, LocatorIF base_address) { super(id, title); this.url = url; this.base_address = base_address; if (base_address == null) { try { base_address = new URILocator(url); } catch (MalformedURLException e) { throw new OntopiaRuntimeException(e); // impossible error } } } /** * INTERNAL: Returns the URL of the topic map pointed at. */ public URL getURL() { return url; } /** * INTERNAL: Returns the base address locator to be used when loading * the topic map. */ public LocatorIF getBaseAddress() { return base_address; } /** * INTERNAL: Sets the base address locator to be used when loading * the topic map. */ public void setBaseAddress(LocatorIF base_address) { this.base_address = base_address; } /** * INTERNAL: Gets the duplicate suppression flag. If the flag is * true duplicate suppression is to be performed when loading the * topic maps. * * @since 1.4.2 */ public boolean getDuplicateSuppression() { return duplicate_suppression; } /** * INTERNAL: Sets the duplicate suppression flag. If the flag is * true duplicate suppression is to be performed when loading the * topic maps. * * @since 1.4.2 */ public void setDuplicateSuppression(boolean duplicate_suppression) { this.duplicate_suppression = duplicate_suppression; } /** * INTERNAL: Flag that indicates whether the same store should be * returned by the createStore(boolean) method on every. If the flag * is false then a new store will be returned every time. Returning * a new store every time effectively means that the referenced * topic map will be loaded on every method call. * * @since 2.1 */ public boolean getReuseStore() { return reuse_store; } /** * INTERNAL: Sets the reuse_store flag. * * @since 2.1 */ public void setReuseStore(boolean reuse_store) { this.reuse_store = reuse_store; } public synchronized void open() { // ignore if already open if (isOpen()) return; if (isDeleted()) throw new StoreDeletedException("Topic map has been deleted through this reference."); // make sure store is loaded if (reuse_store && store == null) { // load topic map store boolean readonly = false; // WARNING: store always read-write!!! TopicMapStoreIF store = null; try { store = loadTopicMap(readonly).getStore(); } catch (IOException e) { throw new OntopiaRuntimeException(e); } // register store store.setReference(this); // register listeners ((AbstractTopicMapStore)store).setTopicListeners(getTopicListeners()); this.store = store; } this.isopen = true; } public synchronized void close() { // close and dereference store if (store != null) { if (store.isOpen()) store.close(); store = null; } this.isopen = false; } /** * INTERNAL: Deletes the topic map pointed to. The reference is closed * before the topic map is deleted. Note that only URIs pointing to * through files can actually be deleted, i.e. "file:" URLs. * * @since 1.3.2 */ public synchronized void delete() { if (source == null) throw new UnsupportedOperationException("This reference cannot be deleted as it does not belong to a source."); if (!source.supportsDelete()) throw new UnsupportedOperationException("This reference cannot be deleted as the source does not allow deleting."); // ignore if store already deleted if (isDeleted()) return; // close reference close(); // delete file. if ("file".equals(url.getProtocol())) { File file = new File(url.getFile()); // FIXME: complain if file does not exist? file.delete(); } this.deleted = true; } public synchronized TopicMapStoreIF createStore(boolean readonly) throws IOException { if (!isOpen()) open(); if (reuse_store && store != null) return store; // load topic map store TopicMapStoreIF store = loadTopicMap(readonly).getStore(); // register store store.setReference(this); // register listeners ((AbstractTopicMapStore)store).setTopicListeners(getTopicListeners()); if (reuse_store) this.store = store; return store; } protected abstract TopicMapIF loadTopicMap(boolean readonly) throws IOException; public String toString() { return super.toString() + " [" + url.toString() + "]"; } /** * INTERNAL: Returns true if stores will keep underlying fulltext * indexes up-to-date. * @return True if fulltext indexes are maintained. * @since 3.0 */ public boolean getMaintainFulltextIndexes() { return maintainFulltextIndexes; } /** * INTERNAL: Specifies whether underlying fulltext indexes are to be * kept up-to-date or not. * @param maintainFulltextIndexes True if fulltext indexes are maintained. * @since 3.0 */ public void setMaintainFulltextIndexes(boolean maintainFulltextIndexes) { this.maintainFulltextIndexes = maintainFulltextIndexes; } public String getIndexDirectory() { return indexDirectory; } public void setIndexDirectory(String indexDirectory) { this.indexDirectory = indexDirectory; } protected void setTopicListeners(TopicMapListenerIF[] topic_listeners) { super.setTopicListeners(topic_listeners); if (reuse_store && store != null) { // register listeners ((AbstractTopicMapStore)store).setTopicListeners(getTopicListeners()); } } }