Permalink
Browse files

Added <o:graphicImage>.

  • Loading branch information...
1 parent 0b155f6 commit 85bfbdf5d489150575f0dc1b1d6a83f951663bb7 @BalusC BalusC committed Aug 25, 2014
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2014 OmniFaces.
+ *
+ * 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.omnifaces.component.output;
+
+import static org.omnifaces.resourcehandler.DefaultResource.RES_NOT_FOUND;
+import static org.omnifaces.util.Renderers.writeAttributes;
+import static org.omnifaces.util.Utils.coalesce;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.faces.application.Application;
+import javax.faces.application.Resource;
+import javax.faces.component.FacesComponent;
+import javax.faces.component.html.HtmlGraphicImage;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+
+import org.omnifaces.resourcehandler.GraphicResource;
+import org.omnifaces.resourcehandler.GraphicResourceHandler;
+
+/**
+ * <p>
+ * The <code>&lt;o:graphicImage&gt;</code> is a component that extends the standard <code>&lt;h:graphicImage&gt;</code>
+ * with support for referencing an {@link InputStream} or <code>byte[]</code> property in <code>value</code> attribute.
+ * This property must point to a <strong>stateless</strong> <code>@ApplicationScoped</code> bean (both JSF and CDI
+ * scopes are supported). E.g.
+ * <pre>
+ * &#64;Named
+ * &#64;ApplicationScoped
+ * public class ImageStreamer {
+ *
+ * &#64;Inject
+ * private ImageService service;
+ *
+ * public byte[] getById(Long id) {
+ * return service.getContent(id);
+ * }
+ *
+ * }
+ * </pre>
+ * <pre>
+ * &lt;ui:repeat value="#{bean.thumbnails}" var="thumbnail"&gt;
+ * &lt;o:graphicImage value="#{imageStreamer.getById(thumbnail.id)}" /&gt;
+ * &lt;/ui:repeat&gt;
+ * </pre>
+ * <p>
+ * In case your "thumbnail" supports it, you can also supply the "last modified" property which will be used in
+ * <code>ETag</code> and <code>Last-Modified</code> headers and in <code>If-Modified-Since</code> checks, hereby
+ * improving the browser caching. The <code>lastModified</code> attribute supports both {@link Long} and {@link Date}.
+ * <pre>
+ * &lt;ui:repeat value="#{bean.thumbnails}" var="thumbnail"&gt;
+ * &lt;o:graphicImage value="#{imageStreamer.getById(thumbnail.id)}" lastModified="#{thumbnail.lastModified}" /&gt;
+ * &lt;/ui:repeat&gt;
+ * </pre>
+ * <p>
+ * In case the property is a method expression taking arguments, each of those arguments will be converted to string
+ * HTTP request parameter and back to actual objects using the converters registered by class as available via
+ * {@link Application#createConverter(Class)}. So, most of standard types like {@link Long} are already implicitly
+ * supported. In case you need to supply a custom object as argument for some reason, you need to explicitly register
+ * a converter for it yourself via <code>&#64;FacesConverter(forClass)</code>.
+ * <p>
+ * Note: the bean class name and method name will end up in image source URL. Although this is technically harmless and
+ * not tamperable by hackers, you might want to choose a "safe" class and method name for the purpose.
+ * Note: like as in <code>&lt;h:graphicImage&gt;</code>, the <code>value</code> attribute is <strong>ignored</strong>
+ * when the <code>name</code> attribute is specified (for JSF resources).
+ *
+ * @author Bauke Scholtz
+ * @since 2.0
+ * @see GraphicResource
+ * @see GraphicResourceHandler
+ */
+@FacesComponent(GraphicImage.COMPONENT_TYPE)
+public class GraphicImage extends HtmlGraphicImage {
+
+ // Constants ------------------------------------------------------------------------------------------------------
+
+ public static final String COMPONENT_TYPE = "org.omnifaces.component.output.GraphicImage";
+ public static final Map<String, String> ATTRIBUTE_NAMES = collectAttributeNames();
+ private static final Map<String, String> collectAttributeNames() {
+ Map<String, String> attributeNames = new HashMap<>();
+
+ for (PropertyKeys propertyKey : PropertyKeys.values()) {
+ String name = propertyKey.name();
+ attributeNames.put(name, "styleClass".equals(name) ? "class" : propertyKey.toString());
+ }
+
+ return Collections.unmodifiableMap(attributeNames);
+ }
+
+ // Constructors ---------------------------------------------------------------------------------------------------
+
+ /**
+ * Constructs the GraphicImage component.
+ */
+ public GraphicImage() {
+ setRendererType(null);
+ }
+
+ // Actions --------------------------------------------------------------------------------------------------------
+
+ /**
+ * Returns <code>true</code>.
+ */
+ @Override
+ public boolean getRendersChildren() {
+ return true;
+ }
+
+ @Override
+ public void encodeChildren(FacesContext context) throws IOException {
+ ResponseWriter writer = context.getResponseWriter();
+ writer.startElement("img", this);
+ writer.writeURIAttribute("src", getSrc(context), "value");
+ writeAttributes(writer, this, GraphicImage.ATTRIBUTE_NAMES);
+ writer.endElement("img");
+ }
+
+ /**
+ * Returns the URL needed for the 'src' attribute.
+ * @param context The involved faces context.
+ * @return The URL needed for the 'src' attribute.
+ */
+ protected String getSrc(FacesContext context) {
+ String name = (String) getAttributes().get("name");
+ String library = (String) getAttributes().get("library");
+
+ Resource resource = null;
+
+ if (name != null) {
+ resource = context.getApplication().getResourceHandler().createResource(name, library);
+ }
+ else {
+ resource = GraphicResource.create(context, this);
+ }
+
+ if (resource != null) {
+ return context.getExternalContext().encodeResourceURL(resource.getRequestPath());
+ }
+ else {
+ return RES_NOT_FOUND;
+ }
+ }
+
+ /**
+ * Returns an empty string as default value instead of <code>null</code>, so that the attribute is always rendered,
+ * as mandated by HTML5.
+ */
+ @Override
+ public String getAlt() {
+ return coalesce(super.getAlt(), "");
+ }
+
+}
@@ -1,5 +1,7 @@
package org.omnifaces.el;
+import static org.omnifaces.el.functions.Strings.capitalize;
+
import java.lang.reflect.Method;
import javax.el.ELContext;
@@ -56,7 +58,8 @@ public static MethodReference getMethodReference(ELContext context, ValueExpress
}
/**
- * Finds a method based on the method name only. Does not support overloaded methods.
+ * Finds a method based on the method name only, if necessary prefixed with "get".
+ * Does not support overloaded methods.
*
* @param base the object in which the method is to be found
* @param methodName name of the method to be found
@@ -70,6 +73,10 @@ public static Method findMethod(Object base, String methodName) {
}
}
+ if (!methodName.startsWith("get")) {
+ return findMethod(base, "get" + capitalize(methodName));
+ }
+
return null;
}
Oops, something went wrong.

0 comments on commit 85bfbdf

Please sign in to comment.