X-Git-Url: http://wamblee.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmain%2Fjava%2Forg%2Fwamblee%2Fphotos%2Fmodel%2Fauthorization%2FAuthorizedAlbum.java;fp=src%2Fmain%2Fjava%2Forg%2Fwamblee%2Fphotos%2Fmodel%2Fauthorization%2FAuthorizedAlbum.java;h=7406d9985f6e5e3308c8fab514a47c3514ecb82b;hb=8845e7fe6141ccc98fd070ee4e653941f6e60508;hp=0000000000000000000000000000000000000000;hpb=b5dd7f771153492ebf5b70949dba8914af58a3cd;p=photos diff --git a/src/main/java/org/wamblee/photos/model/authorization/AuthorizedAlbum.java b/src/main/java/org/wamblee/photos/model/authorization/AuthorizedAlbum.java new file mode 100644 index 0000000..7406d99 --- /dev/null +++ b/src/main/java/org/wamblee/photos/model/authorization/AuthorizedAlbum.java @@ -0,0 +1,233 @@ +/* + * Copyright 2005 the original author or authors. + * + * 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.wamblee.photos.model.authorization; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.wamblee.cache.Cache; +import org.wamblee.cache.CachedObject; +import org.wamblee.photos.model.Album; +import org.wamblee.photos.model.Path; +import org.wamblee.photos.model.Photo; +import org.wamblee.photos.model.PhotoEntry; +import org.wamblee.security.authorization.AllOperation; +import org.wamblee.security.authorization.AuthorizationService; +import org.wamblee.security.authorization.DeleteOperation; +import org.wamblee.security.authorization.ReadOperation; +import org.wamblee.security.authorization.WriteOperation; + +/** + * Decorator for an album providing defined behavior when used in a concurrent + * setting. + */ +public class AuthorizedAlbum extends AuthorizedPhotoEntry implements Album { + + private static final Logger LOGGER = Logger + .getLogger(AuthorizedAlbum.class); + + private AuthorizationService _authorizer; + + private CachedObject> _authorizedEntries; + + private String _sessionId; + + /** + * Constructs concurrent album as a decorator for an album implementation. + * + * @param aAlbum + * Album to decorate. + */ + public AuthorizedAlbum(Album aAlbum, AuthorizationService aService, + Cache aCache, String aSessionId) { + super(aAlbum); + _authorizer = aService; + _authorizedEntries = new CachedObject>( + aCache, aSessionId + "/" + aAlbum.getPath(), + new CachedObject.Computation>() { + public ArrayList getObject(String aObjectKey) { + return AuthorizedAlbum.this.compute(); + } + }); + _sessionId = aSessionId; + } + + /** + * Computes the cache of photo entries to which read access is allowed. + * + * @return Photo entries to which read access is allowed. + */ + private synchronized ArrayList compute() { + LOGGER.info("Refreshing cache " + getPath()); + ArrayList result = new ArrayList(); + for (int i = 0; i < decorated().size(); i++) { + PhotoEntry entry = decorated().getEntry(i); + if (_authorizer.isAllowed(entry, new ReadOperation())) { + result.add(decorate(entry)); // subscription will take place + // automatically. + } + } + return result; + } + + private Album decorated() { + return (Album) getEntry(); + } + + /** + * Creates a decorate for the photo entry to make it safe for concurrent + * access. + * + * @param aEntry + * Entry to decorate + * @return Decorated photo. + */ + private T decorate(T aEntry) { + if (aEntry == null) { + return null; + } else if (aEntry instanceof Photo) { + return (T) new AuthorizedPhoto((Photo) aEntry); + } else if (aEntry instanceof Album) { + return (T) new AuthorizedAlbum((Album) aEntry, _authorizer, + _authorizedEntries.getCache(), _sessionId); + } else { + throw new IllegalArgumentException( + "Entry is neither a photo nor an album: " + aEntry); + } + } + + /* + * (non-Javadoc) + * + * @see org.wamblee.photos.model.Album#getEntry(java.lang.String) + */ + public PhotoEntry getEntry(String aPath) { + return getEntry(new Path(aPath)); + } + + /* + * (non-Javadoc) + * + * @see org.wamblee.photos.model.Album#getEntry(org.wamblee.photos.model.Path) + */ + public PhotoEntry getEntry(Path aPath) { + if (aPath.isRoot()) { + return this; + } + List cache = _authorizedEntries.get(); + String id = aPath.getPart(0); + Path remainder = aPath.remainder(); + for (PhotoEntry entry : cache) { + if (entry.getId().equals(id)) { + if (remainder.isRoot()) { + return entry; + } else { + if (!(entry instanceof Album)) { + throw new IllegalArgumentException(getPath() + " " + + aPath); + } + return ((Album) entry).getEntry(remainder); + } + } + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.wamblee.photos.model.Album#getEntry(int) + */ + public PhotoEntry getEntry(int aIndex) { + return _authorizedEntries.get().get(aIndex); + } + + /* + * (non-Javadoc) + * + * @see org.wamblee.photos.model.Album#size() + */ + public int size() { + return _authorizedEntries.get().size(); + } + + /* + * (non-Javadoc) + * + * @see org.wamblee.photos.model.Album#addImage(java.lang.String, + * java.io.InputStream) + */ + public void addImage(String aId, InputStream aImage) throws IOException { + _authorizer.check(this, new WriteOperation()); + _authorizedEntries.invalidate(); + decorated().addImage(aId, aImage); + } + + /* + * (non-Javadoc) + * + * @see org.wamblee.photos.model.Album#addAlbum(java.lang.String) + */ + public void addAlbum(String aId) throws IOException { + _authorizer.check(this, new WriteOperation()); + _authorizedEntries.invalidate(); + decorated().addAlbum(aId); + } + + /* + * (non-Javadoc) + * + * @see org.wamblee.photos.model.Album#removeEntry(java.lang.String) + */ + public void removeEntry(String aId) throws IOException { + // Check whether deletion is allowed. + PhotoEntry entry = _authorizer.check(decorated().getEntry("/" + aId), + new DeleteOperation()); + _authorizedEntries.invalidate(); + decorated().removeEntry(aId); + } + + public Photo findPhotoBefore(String aId) { + Photo entry = decorated().findPhotoBefore(aId); + while (entry != null + && !_authorizer.isAllowed(entry, new AllOperation())) { + entry = decorated().findPhotoBefore(entry.getId()); + } + return decorate(entry); + } + + public Photo findPhotoAfter(String aId) { + Photo entry = decorated().findPhotoAfter(aId); + while (entry != null + && !_authorizer.isAllowed(entry, new AllOperation())) { + entry = decorated().findPhotoAfter(entry.getId()); + } + return decorate(entry); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "AuthorizedAlbum(path = '" + decorated().getPath() + "')"; + } +}