Package org.apache.wicket.markup.html.image.resource

Source Code of org.apache.wicket.markup.html.image.resource.LocalizedImageResource$SimpleStaticResourceReference

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.wicket.markup.html.image.resource;

import java.util.Locale;

import org.apache.wicket.Application;
import org.apache.wicket.Component;
import org.apache.wicket.IClusterable;
import org.apache.wicket.IResourceFactory;
import org.apache.wicket.IResourceListener;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.border.Border;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.handler.resource.ResourceReferenceRequestHandler;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.request.resource.IResource;
import org.apache.wicket.request.resource.IResource.Attributes;
import org.apache.wicket.request.resource.PackageResourceReference;
import org.apache.wicket.request.resource.ResourceReference;
import org.apache.wicket.util.lang.Objects;
import org.apache.wicket.util.parse.metapattern.Group;
import org.apache.wicket.util.parse.metapattern.MetaPattern;
import org.apache.wicket.util.parse.metapattern.OptionalMetaPattern;
import org.apache.wicket.util.parse.metapattern.parsers.MetaPatternParser;
import org.apache.wicket.util.string.Strings;


/**
* THIS CLASS IS INTENDED FOR INTERNAL USE IN IMPLEMENTING LOCALE SENSITIVE COMPONENTS THAT USE
* IMAGE RESOURCES AND SHOULD NOT BE USED DIRECTLY BY END-USERS.
* <p>
* This class contains the logic for extracting static image resources referenced by the SRC
* attribute of component tags and keeping these static image resources in sync with the component
* locale.
* <p>
* If no image is specified by the SRC attribute of an IMG tag, then any VALUE attribute is
* inspected. If there is a VALUE attribute, it must be of the form
* "[factoryName]:[sharedImageName]?:[specification]". [factoryName] is the name of a resource
* factory that has been added to Application (for example, DefaultButtonImageResourceFactory is
* installed by default under the name "buttonFactory"). The [sharedImageName] value is optional and
* gives a name under which a given generated image is shared. For example, a cancel button image
* generated by the VALUE attribute "buttonFactory:cancelButton:Cancel" is shared under the name
* "cancelButton" and this specification will cause a component to reference the same image resource
* no matter what page it appears on, which is a very convenient and efficient way to create and
* share images. The [specification] string which follows the second colon is passed directly to the
* image factory and its format is dependent on the specific image factory. For details on the
* default buttonFactory, see
* {@link org.apache.wicket.markup.html.image.resource.DefaultButtonImageResourceFactory}.
* <p>
* Finally, if there is no SRC attribute and no VALUE attribute, the Image component's model is
* inspected. If the model contains a resource or resource reference, this image is used, otherwise
* the model is converted to a String and that value is used as a path to load the image.
*
* @author Jonathan Locke
*/
public final class LocalizedImageResource implements IClusterable
{
  private static final long serialVersionUID = 1L;

  /**
   * What kind of resource it is. TRUE==Resource is set, FALSE==ResourceReference is set, null
   * none
   */
  private Boolean resourceKind;

  /** The component that is referencing this image resource */
  private final Component component;

  /** The image resource this image component references */
  private IResource resource;

  /** The resource reference */
  private ResourceReference resourceReference;

  /** The resource parameters */
  private PageParameters resourceParameters;

  /** The locale of the image resource */
  private Locale locale;

  /** The style of the image resource */
  private String style;

  /** The component's variation (of the style) */
  private String variation;

  /**
   * Parses image value specifications of the form "[factoryName]:
   * [shared-image-name]?:[specification]"
   *
   * @author Jonathan Locke
   */
  private static final class ImageValueParser extends MetaPatternParser
  {
    /** Factory name */
    private static final Group factoryName = new Group(MetaPattern.VARIABLE_NAME);

    /** Image reference name */
    private static final Group imageReferenceName = new Group(MetaPattern.VARIABLE_NAME);

    /** Factory specification string */
    private static final Group specification = new Group(MetaPattern.ANYTHING_NON_EMPTY);

    /** Meta pattern. */
    private static final MetaPattern pattern = new MetaPattern(new MetaPattern[] { factoryName,
        MetaPattern.COLON,
        new OptionalMetaPattern(new MetaPattern[] { imageReferenceName }),
        MetaPattern.COLON, specification });

    /**
     * Construct.
     *
     * @param input
     *            to parse
     */
    private ImageValueParser(final CharSequence input)
    {
      super(pattern, input);
    }

    /**
     * @return The factory name
     */
    private String getFactoryName()
    {
      return factoryName.get(matcher());
    }

    /**
     * @return Returns the imageReferenceName.
     */
    private String getImageReferenceName()
    {
      return imageReferenceName.get(matcher());
    }

    /**
     * @return Returns the specification.
     */
    private String getSpecification()
    {
      return specification.get(matcher());
    }
  }

  /**
   * Constructor
   *
   * @param component
   *            The component that owns this localized image resource
   */
  public LocalizedImageResource(final Component component)
  {
    this.component = component;
    locale = component.getLocale();
    style = component.getStyle();
    variation = component.getVariation();
  }

  /**
   * Binds this resource if it is shared
   */
  public final void bind()
  {
    // If we have a resource reference
    if (resourceReference != null)
    {
      component.getApplication()
        .getResourceReferenceRegistry()
        .registerResourceReference(resourceReference);
      // Bind the reference to the application
    }
  }

  public final void onResourceRequested(PageParameters parameters)
  {
    bind();
    RequestCycle requestCycle = RequestCycle.get();
    Attributes attributes = new Attributes(requestCycle.getRequest(),
      requestCycle.getResponse(), parameters);
    resource.respond(attributes);
  }

  /**
   * @param resource
   *            The resource to set.
   */
  public final void setResource(final IResource resource)
  {
    if (this.resource != resource)
    {
      resourceKind = Boolean.TRUE;
      this.resource = resource;
    }
  }

  /**
   * @param resourceReference
   *            The resource to set.
   */
  public final void setResourceReference(final ResourceReference resourceReference)
  {
    setResourceReference(resourceReference, resourceParameters);
  }

  /**
   * @return true if it has a resourceReference. (it points to a shared resource)
   */
  public final boolean isStateless()
  {
    return resourceReference != null;
  }

  /**
   * @param resourceReference
   *            The resource to set.
   * @param resourceParameters
   *            The resource parameters for the shared resource
   */
  public final void setResourceReference(final ResourceReference resourceReference,
    final PageParameters resourceParameters)
  {
    if (resourceReference != this.resourceReference)
    {
      resourceKind = Boolean.FALSE;
      this.resourceReference = resourceReference;
    }
    this.resourceParameters = resourceParameters;
    bind();
  }

  /**
   * @param tag
   *            The tag to inspect for an optional src attribute that might reference an image.
   * @throws WicketRuntimeException
   *             Thrown if an image is required by the caller, but none can be found.
   */
  public final void setSrcAttribute(final ComponentTag tag)
  {
    // If locale has changed from the initial locale used to attach image
    // resource, then we need to reload the resource in the new locale
    Locale l = component.getLocale();
    String s = component.getStyle();
    String v = component.getVariation();
    if (resourceKind == null &&
      (!Objects.equal(locale, l) || !Objects.equal(style, s) || !Objects.equal(variation, v)))
    {
      // Get new component locale and style
      locale = l;
      style = s;
      variation = v;

      // Invalidate current resource so it will be reloaded/recomputed
      resourceReference = null;
      resource = null;
    }
    else
    {
      // TODO post 1.2: should we have support for locale changes when the
      // resource reference (or resource??) is set manually..
      // We should get a new resource reference for the current locale
      // then that points to the same resource but with another locale if
      // it exists. Something like
      // SharedResource.getResourceReferenceForLocale(resourceReference);
    }

    // check if the model contains a resource, if so, load the resource from
    // the model.
    Object modelObject = component.getDefaultModelObject();
    if (modelObject instanceof ResourceReference)
    {
      resourceReference = (ResourceReference)modelObject;
    }
    else if (modelObject instanceof IResource)
    {
      resource = (IResource)modelObject;
    }

    // FIXME NG
    // Not yet supported

    // Need to load image resource for this component?
    if (resource == null && resourceReference == null)
    {
      // Get SRC attribute of tag
      final CharSequence src = tag.getString("src");
      if (src != null)
      {
        // Try to load static image
        loadStaticImage(src.toString());
      }
      else
      {
        // Get VALUE attribute of tag
        final CharSequence value = tag.getString("value");
        if (value != null)
        {
          // Try to generate an image using an image factory
          newImage(value);
        }
        else
        {
          // Load static image using model object as the path
          loadStaticImage(component.getDefaultModelObjectAsString());
        }
      }
    }

    // Get URL for resource
    final CharSequence url;
    if (resourceReference != null)
    {
      // Create URL to shared resource
      IRequestHandler handler = new ResourceReferenceRequestHandler(resourceReference,
        resourceParameters);
      url = RequestCycle.get().renderUrlFor(handler);
    }
    else
    {
      // Create URL to component
      url = component.urlFor(IResourceListener.INTERFACE);
    }

    // Set the SRC attribute to point to the component or shared resource
    tag.put(
      "src",
      RequestCycle.get()
        .getOriginalResponse()
        .encodeURL(Strings.replaceAll(url, "&", "&amp;")));
  }

  /**
   * @param application
   *            The application
   * @param factoryName
   *            The name of the image resource factory
   * @return The resource factory
   * @throws WicketRuntimeException
   *             Thrown if factory cannot be found
   */
  private IResourceFactory getResourceFactory(final Application application,
    final String factoryName)
  {
    final IResourceFactory factory = application.getResourceSettings().getResourceFactory(
      factoryName);

    // Found factory?
    if (factory == null)
    {
      throw new WicketRuntimeException("Could not find image resource factory named " +
        factoryName);
    }
    return factory;
  }


  static class SimpleStaticResourceReference extends ResourceReference
  {
    final IResource resource;

    public SimpleStaticResourceReference(Class<?> scope, String name, Locale locale,
      String style, String variation, IResource resource)
    {
      super(scope, name, locale, style, variation);
      this.resource = resource;
    }

    private static final long serialVersionUID = 1L;

    @Override
    public IResource getResource()
    {
      return resource;
    }

  };

  /**
   * Tries to load static image at the given path and throws an exception if the image cannot be
   * located.
   *
   * @param path
   *            The path to the image
   * @throws WicketRuntimeException
   *             Thrown if the image cannot be located
   */
  @SuppressWarnings("unchecked")
  private void loadStaticImage(final String path)
  {
    MarkupContainer parent = component.findParentWithAssociatedMarkup();
    if (parent instanceof Border)
    {
      parent = parent.getParent();
    }
    final Class<?> scope = parent.getClass();
    resourceReference = new PackageResourceReference(scope, path, locale, style, variation);
    bind();
  }

  /**
   * Generates an image resource based on the attribute values on tag
   *
   * @param value
   *            The value to parse
   */
  private void newImage(final CharSequence value)
  {
    // Parse value
    final ImageValueParser valueParser = new ImageValueParser(value);

    // Does value match parser?
    if (valueParser.matches())
    {
      final String imageReferenceName = valueParser.getImageReferenceName();
      final String specification = Strings.replaceHtmlEscapeNumber(valueParser.getSpecification());
      final String factoryName = valueParser.getFactoryName();
      final Application application = component.getApplication();

      // Do we have a reference?
      if (!Strings.isEmpty(imageReferenceName))
      {
        // Is resource already available via the application?
        if (application.getResourceReferenceRegistry().getResourceReference(
          Application.class, imageReferenceName, locale, style, variation, true) == null)
        {
          // Resource not available yet, so create it with factory and
          // share via Application
          final IResource imageResource = getResourceFactory(application, factoryName).newResource(
            specification, locale, style, variation);

          ResourceReference ref = new SimpleStaticResourceReference(Application.class,
            imageReferenceName, locale, style, variation, imageResource);

          application.getResourceReferenceRegistry().registerResourceReference(ref);
        }

        // Create resource reference
        resourceReference = new PackageResourceReference(Application.class,
          imageReferenceName, locale, style, variation);
      }
      else
      {
        resource = getResourceFactory(application, factoryName).newResource(specification,
          locale, style, variation);
      }
    }
    else
    {
      throw new WicketRuntimeException(
        "Could not generate image for value attribute '" +
          value +
          "'.  Was expecting a value attribute of the form \"[resourceFactoryName]:[resourceReferenceName]?:[factorySpecification]\".");
    }
  }

  /**
   * return the resource
   *
   * @return resource or <code>null</code> if there is none
   */
  public final IResource getResource()
  {
    return resource;
  }

  /**
   * return the resource
   *
   * @return resource or <code>null</code> if there is none
   */
  public final ResourceReference getResourceReference()
  {
    return resourceReference;
  }
}
TOP

Related Classes of org.apache.wicket.markup.html.image.resource.LocalizedImageResource$SimpleStaticResourceReference

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.