EntryNamesContext.java

/*
 * Copyright (c) 2007-2017 MetaSolutions AB
 *
 * 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.entrystore.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.Statement;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.repository.RepositoryException;
import org.entrystore.Entry;
import org.entrystore.PrincipalManager;
import org.entrystore.PrincipalManager.AccessProperty;
import org.entrystore.repository.RepositoryEvent;
import org.entrystore.repository.RepositoryEventObject;

import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Set;


/**
 * Creates a 
 * @author Olov Wikberg, IML UmeƄ University
 * @author matthias
 *
 */
public class EntryNamesContext extends ContextImpl {
	private static final Log log = LogFactory.getLog(EntryNamesContext.class);

	HashMap<String, URI> names2EntryURI;
	HashMap<URI, String> entryURI2Name;

	
	/**
	 * Creates a principal manager
	 * @param entry this principal managers entry
	 * @param uri this principal managers URI 
	 * @param cache
	 */
	public EntryNamesContext(EntryImpl entry, String uri, SoftCache cache) {
		super(entry, uri, cache);
	}

	protected String getName(URI entryURI) {
		if(names2EntryURI == null) {
			loadNameIndex();
		}

		return entryURI2Name.get(entryURI);
	}

	public Entry getEntryByName(String name) {
		if(names2EntryURI == null) {
			loadNameIndex();
		}

		return getByEntryURI(names2EntryURI.get(name));
	}

    protected void removeFromIndex(EntryImpl entry, RepositoryConnection rc) throws RepositoryException {
        super.removeFromIndex(entry, rc);
        if(names2EntryURI == null) {
            loadNameIndex();
        }

        URI entryURI = entry.getEntryURI();
        IRI cURI = rc.getValueFactory().createIRI(entryURI.toString());

        if (entryURI2Name.containsKey(entryURI)) {
            String oldName = entryURI2Name.get(entryURI);
            entryURI2Name.remove(entryURI);
            names2EntryURI.remove(oldName);
            Literal oldAliasLiteral = rc.getValueFactory().createLiteral(oldName);
            rc.remove(cURI, RepositoryProperties.alias, oldAliasLiteral, this.resourceURI);
        }
    }

    protected boolean setEntryName(URI entryURI, String newName) {
        if (entryURI == null) {
			throw new IllegalArgumentException("Arguments must not be null");
		}
		
		Entry forEntry = getByEntryURI(entryURI);
		if (forEntry == null) {
			//Entry must exist to allow Name to be set.
			throw new org.entrystore.repository.RepositoryException("Unable to set name for non-existing entry");
		}
		
		PrincipalManager pm = this.entry.getRepositoryManager().getPrincipalManager();
		if (pm != null) {
			pm.checkAuthenticatedUserAuthorized(forEntry, AccessProperty.WriteResource);
		}
		if(names2EntryURI == null) {
			loadNameIndex();
		}

		if (newName != null && names2EntryURI.containsKey(newName)) {
			if (newName.equals(entryURI2Name.get(entryURI))) {
				return true;
			} else {
				log.error("The name "+newName+" is already in use.");
				return false;
			}
		}

		try {
			synchronized (this.entry.repository) {
				RepositoryConnection rc = entry.repository.getConnection();
				try {
					ValueFactory vf = entry.repository.getValueFactory();
					rc.begin();
					IRI cURI = vf.createIRI(entryURI.toString());
					if (entryURI2Name.containsKey(entryURI)) {
						String oldName = entryURI2Name.get(entryURI);
						entryURI2Name.remove(entryURI);
						names2EntryURI.remove(oldName);
						Literal oldAliasLiteral = vf.createLiteral(oldName);
						rc.remove(cURI, RepositoryProperties.alias, oldAliasLiteral, this.resourceURI);
					}
					if (newName != null) {
						names2EntryURI.put(newName, entryURI);
						entryURI2Name.put(entryURI, newName);
						Literal nameLiteral = vf.createLiteral(newName);
						rc.add(cURI, RepositoryProperties.alias, nameLiteral, this.resourceURI);
						this.entry.updateModifiedDateSynchronized(rc, vf);
						((EntryImpl) forEntry).updateModifiedDateSynchronized(rc, vf);
					}
					rc.commit();
					entry.getRepositoryManager().fireRepositoryEvent(new RepositoryEventObject(entry, RepositoryEvent.ResourceUpdated));
					entry.getRepositoryManager().fireRepositoryEvent(new RepositoryEventObject(forEntry, RepositoryEvent.ResourceUpdated));
					return true;
				} catch (Exception e) {
					rc.rollback();
					throw new org.entrystore.repository.RepositoryException("Error in connection to repository", e);
				} finally {
					log.info("Successfully set the name " + newName + " for entry with URI: " + entryURI);
					rc.close();
				}
			}
		} catch (RepositoryException e) {
			throw new org.entrystore.repository.RepositoryException("Cannot connect to repository", e);
		}
	}

	private void loadNameIndex() {
		try {
			synchronized (this.entry.repository) {
				if (names2EntryURI != null) {
					return;
				}
				RepositoryConnection rc = entry.repository.getConnection();
				try {
					names2EntryURI = new HashMap<String, URI>();
					entryURI2Name = new HashMap<URI, String>();
					List<Statement> statements = rc.getStatements(null, RepositoryProperties.alias, null, false, this.resourceURI).asList();
					for (Statement statement : statements) {
						try {
							URI entryURI = URI.create(statement.getSubject().stringValue());
							String name = statement.getObject().stringValue();
							names2EntryURI.put(name, entryURI);
							entryURI2Name.put(entryURI, name);
						} catch (Exception e) {
							log.error(e.getMessage());
							throw new org.entrystore.repository.RepositoryException("Error in connection to repository", e);
						}
					}
				} finally {
					rc.close();
				}
			}
		} catch (RepositoryException e) {
			log.error(e.getMessage());
			throw new org.entrystore.repository.RepositoryException("Cannot connect to repository", e);
		}
	}
	
	protected Set<String> getEntryNames() {
		checkAccess(null, AccessProperty.ReadResource);
		if(names2EntryURI == null) {
			loadNameIndex();
		}

		return names2EntryURI.keySet();
	}

}