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.log4j.Logger;
032    
033    import org.apache.isis.core.commons.debug.DebugString;
034    import org.apache.isis.core.commons.exceptions.IsisException;
035    import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
036    import org.apache.isis.core.metamodel.spec.ObjectSpecification;
037    
038    /**
039     * ImageLookup provides an efficient way of finding the most suitable image to
040     * use. It ensures that an image is always available, providing a default image
041     * if needed. All requests are cached to improve performance.
042     */
043    // TODO allow for multiple extension types
044    public class ImageLookup {
045        private static final Logger LOG = Logger.getLogger(ImageLookup.class);
046        private static final String UNKNOWN_IMAGE = "Default";
047        private static final String[] EXTENSIONS = { "png", "gif", "jpg", "jpeg" };
048        private static final Map images = new HashMap();
049        private static String imageDirectory;
050        // private static String unknownImageFile;
051        private static ServletContext context;
052    
053        public static void setImageDirectory(final ServletContext context, String imageDirectory) {
054            LOG.debug("image directory required for: " + imageDirectory);
055            ImageLookup.context = context;
056            imageDirectory = (imageDirectory.startsWith("/") ? "" : "/") + imageDirectory + "/";
057            final Set resourcePaths = context.getResourcePaths(imageDirectory);
058            if (resourcePaths == null || resourcePaths.size() == 0) {
059                throw new IsisException("No image directory found: " + imageDirectory);
060            }
061            LOG.info("image directory set to: " + imageDirectory);
062            ImageLookup.imageDirectory = imageDirectory;
063        }
064    
065        public static void debug(final DebugString debug) {
066            debug.appendTitle("Image Lookup");
067            debug.indent();
068            final Iterator keys = images.keySet().iterator();
069            while (keys.hasNext()) {
070                final Object key = keys.next();
071                final Object value = images.get(key);
072                debug.appendln(key + " -> " + value);
073            }
074            debug.unindent();
075        }
076    
077        private static String imageFile(final String imageName, final String contextPath) {
078            for (final String element : EXTENSIONS) {
079                URL resource;
080                try {
081                    final String imagePath = imageDirectory + imageName + "." + element;
082                    resource = context.getResource(imagePath);
083                    if (resource != null) {
084                        LOG.debug("image found at " + contextPath + imagePath);
085                        return contextPath + imagePath;
086                    }
087                    final URL onClasspath = ImageLookup.class.getResource(imagePath);
088                    if (onClasspath != null) {
089                        LOG.debug("image found on classpath " + onClasspath);
090                        return contextPath + imagePath;
091                    }
092                } catch (final MalformedURLException ignore) {
093                }
094            }
095            return null;
096        }
097    
098        private static String findImage(final ObjectSpecification specification, final String contextPath) {
099            String path = findImageFor(specification, contextPath);
100            if (path == null) {
101                path = imageFile(UNKNOWN_IMAGE, contextPath);
102            }
103            return path;
104        }
105    
106        private static String findImageFor(final ObjectSpecification specification, final String contextPath) {
107            final String name = specification.getShortIdentifier();
108            final String fileName = imageFile(name, contextPath);
109            if (fileName != null) {
110                images.put(name, fileName);
111                return fileName;
112            } else {
113                for (final ObjectSpecification interfaceSpec : specification.interfaces()) {
114                    final String path = findImageFor(interfaceSpec, contextPath);
115                    if (path != null) {
116                        return path;
117                    }
118                }
119                final ObjectSpecification superclass = specification.superclass();
120                if (superclass != null) {
121                    return findImageFor(superclass, contextPath);
122                } else {
123                    return null;
124                }
125            }
126        }
127    
128        /**
129         * For an object, the icon name from the object is return if it is not null,
130         * otherwise the specification is used to look up a suitable image name.
131         * 
132         * @param contextPath
133         * 
134         * @see ObjectAdapter#getIconName()
135         * @see #imagePath(ObjectSpecification)
136         */
137        /*
138         * public static String imagePath(ObjectAdapter object) { String iconName =
139         * object.getIconName(); if (iconName != null) { return imagePath(iconName);
140         * } else { return imagePath(object.getSpecification()); } }
141         */
142        public static String imagePath(final ObjectSpecification specification, final String contextPath) {
143            final String name = specification.getShortIdentifier();
144            final String imageName = (String) images.get(name);
145            if (imageName != null) {
146                return imageName;
147            } else {
148                return findImage(specification, contextPath);
149            }
150        }
151    
152        /*
153         * public static String imagePath(String name) { String imageName = (String)
154         * images.get(name); if (imageName != null) { return (String) imageName; }
155         * else { String fileName = imageFile(name); return fileName == null ?
156         * unknownImageFile : fileName; } }
157         */
158    
159        public static String imagePath(final ObjectAdapter object, final String contextPath) {
160            final String name = object.getIconName();
161            final String imageName = (String) images.get(name);
162            if (imageName != null) {
163                return imageName;
164            } else {
165                final String imageFile = imageFile(name, contextPath);
166                if (imageFile != null) {
167                    return imageFile;
168                } else {
169                    return findImage(object.getSpecification(), contextPath);
170                }
171            }
172        }
173    }