001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *
010     *        http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License.
018     */
019    
020    package org.apache.isis.viewer.scimpi.servlet;
021    
022    import java.net.MalformedURLException;
023    import java.net.URL;
024    import java.util.HashMap;
025    import java.util.Iterator;
026    import java.util.Map;
027    import java.util.Set;
028    
029    import javax.servlet.ServletContext;
030    
031    import org.apache.isis.core.commons.debug.DebugString;
032    import org.apache.isis.core.commons.exceptions.IsisException;
033    import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
034    import org.apache.isis.core.metamodel.spec.ObjectSpecification;
035    import org.apache.log4j.Logger;
036    
037    /**
038     * ImageLookup provides an efficient way of finding the most suitable image to use. It ensures that an image is always
039     * available, providing a default image if needed. All requests are cached to improve performance.
040     */
041    // TODO allow for multiple extension types
042    public class ImageLookup {
043        private static final Logger LOG = Logger.getLogger(ImageLookup.class);
044        private static final String UNKNOWN_IMAGE = "Default";
045        private static final String[] EXTENSIONS = { "png", "gif", "jpg", "jpeg" };
046        private static final Map images = new HashMap();
047        private static String imageDirectory;
048        // private static String unknownImageFile;
049        private static ServletContext context;
050    
051        public static void setImageDirectory(final ServletContext context, String imageDirectory) {
052            LOG.debug("image directory required for: " + imageDirectory);
053            ImageLookup.context = context;
054            imageDirectory = (imageDirectory.startsWith("/") ? "" : "/") + imageDirectory + "/";
055            final Set resourcePaths = context.getResourcePaths(imageDirectory);
056            if (resourcePaths == null || resourcePaths.size() == 0) {
057                throw new IsisException("No image directory found: " + imageDirectory);
058            }
059            LOG.info("image directory set to: " + imageDirectory);
060            ImageLookup.imageDirectory = imageDirectory;
061        }
062    
063        public static void debug(final DebugString debug) {
064            debug.appendTitle("Image Lookup");
065            debug.indent();
066            final Iterator keys = images.keySet().iterator();
067            while (keys.hasNext()) {
068                final Object key = keys.next();
069                final Object value = images.get(key);
070                debug.appendln(key + " -> " + value);
071            }
072            debug.unindent();
073        }
074    
075        private static String imageFile(final String imageName, final String contextPath) {
076            for (final String element : EXTENSIONS) {
077                URL resource;
078                try {
079                    final String imagePath = imageDirectory + imageName + "." + element;
080                    resource = context.getResource(imagePath);
081                    if (resource != null) {
082                        LOG.debug("image found at " + contextPath + imagePath);
083                        return contextPath + imagePath;
084                    }
085                    final URL onClasspath = ImageLookup.class.getResource(imagePath);
086                    if (onClasspath != null) {
087                        LOG.debug("image found on classpath " + onClasspath);
088                        return contextPath + imagePath;
089                    }
090                } catch (final MalformedURLException ignore) {
091                }
092            }
093            return null;
094        }
095    
096        private static String findImage(final ObjectSpecification specification, final String contextPath) {
097            String path = findImageFor(specification, contextPath);
098            if (path == null) {
099                path = imageFile(UNKNOWN_IMAGE, contextPath);
100            }
101            return path;
102        }
103    
104        private static String findImageFor(final ObjectSpecification specification, final String contextPath) {
105            final String name = specification.getShortIdentifier();
106            final String fileName = imageFile(name, contextPath);
107            if (fileName != null) {
108                images.put(name, fileName);
109                return fileName;
110            } else {
111                for (final ObjectSpecification interfaceSpec : specification.interfaces()) {
112                    final String path = findImageFor(interfaceSpec, contextPath);
113                    if (path != null) {
114                        return path;
115                    }
116                }
117                final ObjectSpecification superclass = specification.superclass();
118                if (superclass != null) {
119                    return findImageFor(superclass, contextPath);
120                } else {
121                    return null;
122                }
123            }
124        }
125    
126        /**
127         * For an object, the icon name from the object is return if it is not null, otherwise the specification is used to
128         * look up a suitable image name.
129         * 
130         * @param contextPath
131         * 
132         * @see ObjectAdapter#getIconName()
133         * @see #imagePath(ObjectSpecification)
134         */
135        /*
136         * public static String imagePath(ObjectAdapter object) { String iconName = object.getIconName(); if (iconName !=
137         * null) { return imagePath(iconName); } else { return imagePath(object.getSpecification()); } }
138         */
139        public static String imagePath(final ObjectSpecification specification, final String contextPath) {
140            final String name = specification.getShortIdentifier();
141            final String imageName = (String) images.get(name);
142            if (imageName != null) {
143                return imageName;
144            } else {
145                return findImage(specification, contextPath);
146            }
147        }
148    
149        /*
150         * public static String imagePath(String name) { String imageName = (String) images.get(name); if (imageName !=
151         * null) { return (String) imageName; } else { String fileName = imageFile(name); return fileName == null ?
152         * unknownImageFile : fileName; } }
153         */
154    
155        public static String imagePath(final ObjectAdapter object, final String contextPath) {
156            final String name = object.getIconName();
157            final String imageName = (String) images.get(name);
158            if (imageName != null) {
159                return imageName;
160            } else {
161                final String imageFile = imageFile(name, contextPath);
162                if (imageFile != null) {
163                    return imageFile;
164                } else {
165                    return findImage(object.getSpecification(), contextPath);
166                }
167            }
168        }
169    }