/* * 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() + "')"; } }