@Override
    public void onComponentTag(final Component component, final ComponentTag tag) {
      String expr = tag.getAttributes().getString(wicketMessageAttrName);
      if (!Strings.isEmpty(expr)) {
        expr = expr.trim();

        String[] attrsAndKeys = Strings.split(expr, ',');

        for (String attrAndKey : attrsAndKeys) {
          int colon = attrAndKey.lastIndexOf(":");
          // make sure the attribute-key pair is valid
          if (attrAndKey.length() < 3 || colon < 1 || colon > attrAndKey.length() - 2) {
            throw new WicketRuntimeException(
                "wicket:message attribute contains an invalid value [["
                    + expr
                    + "]], must be of form (attr:key)+");
          }

          String attr = attrAndKey.substring(0, colon);
          String key = attrAndKey.substring(colon + 1);

          // we need to call the proper getString() method based on
          // whether or not we have a default value
          final String value;
          if (tag.getAttributes().containsKey(attr)) {
            value = component.getString(key, null, tag.getAttributes().getString(attr));
          } else {
            value = component.getString(key);
          }
          tag.put(attr, value);
        }
      }
    }
Exemple #2
0
  public static final Map<String, String[]> parseQueryString(String queryString) {
    Map<String, String[]> parameterMap = new HashMap<String, String[]>();
    if (queryString != null) {
      for (String queryParameter : Strings.split(queryString, '&')) {

        String parts[] = Strings.split(queryParameter, '=');
        if (parts.length > 0) {
          for (int i = 0; (i < 2) && (i < parts.length); i++) {
            parts[i] = UrlDecoder.QUERY_INSTANCE.decode(parts[i], DEFAULT_CHARSET_NAME);
          }

          String[] values = parameterMap.get(parts[0]);
          if (values == null) {
            parameterMap.put(parts[0], new String[] {(parts.length > 1 ? parts[1] : null)});
          } else {
            String[] moreValues = new String[values.length + 1];
            System.arraycopy(values, 0, moreValues, 0, values.length);
            moreValues[values.length - 1] = (parts.length > 1 ? parts[1] : null);
            parameterMap.put(parts[0], moreValues);
          }
        }
      }
    }
    return parameterMap;
  }
Exemple #3
0
 /**
  * Escape single and double quotes so that they can be part of e.g. an alert call.
  *
  * @param input input
  * @return Escaped version of the input
  */
 public static CharSequence escapeQuotes(final CharSequence input) {
   CharSequence s = input;
   if (s != null) {
     s = Strings.replaceAll(s, "'", "\\'");
     s = Strings.replaceAll(s, "\"", "\\\"");
   }
   return s;
 }
 /**
  * initializes the ignore paths parameter
  *
  * @param filterConfig
  */
 private void initIgnorePaths(final FilterConfig filterConfig) {
   String paths = filterConfig.getInitParameter(IGNORE_PATHS_PARAM);
   if (Strings.isEmpty(paths) == false) {
     String[] parts = Strings.split(paths, ',');
     for (String path : parts) {
       path = path.trim();
       if (path.startsWith("/")) {
         path = path.substring(1);
       }
       ignorePaths.add(path);
     }
   }
 }
  /**
   * @param field
   * @return bean name
   */
  private String getBeanName(final Field field) {
    SpringBean annot = field.getAnnotation(SpringBean.class);

    String name;
    boolean required;
    if (annot != null) {
      name = annot.name();
      required = annot.required();
    } else {
      Named named = field.getAnnotation(Named.class);
      name = named != null ? named.value() : "";
      required = false;
    }

    if (Strings.isEmpty(name)) {
      name = beanNameCache.get(field.getType());
      if (name == null) {
        name = getBeanNameOfClass(contextLocator.getSpringContext(), field.getType(), required);

        if (name != null) {
          beanNameCache.put(field.getType(), name);
        }
      }
    }
    return name;
  }
  @SuppressWarnings("unchecked")
  public static void prepareFormComponents(
      FormComponent formComponent,
      boolean isRequired,
      String label,
      int minimumLenght,
      int maximumLenght,
      boolean hasFeedBackPanel) {
    if (isRequired) {
      formComponent.setRequired(true);
    }
    if (!Strings.isEmpty(label)) {
      formComponent.setLabel(new Model<String>(label));
    }
    if (!(minimumLenght < 0)) {
      formComponent.add(StringValidator.minimumLength(minimumLenght));
    }
    if (!(maximumLenght < 0)) {
      formComponent.add(StringValidator.maximumLength(maximumLenght));
    }
    if (hasFeedBackPanel) {
      formComponent
          .getParent()
          .add(
              new FeedbackPanel(
                  formComponent.getId() + "FeedbackPanel",
                  new ComponentFeedbackMessageFilter(formComponent)));
    }

    // Add input behaviour
    formComponent.add(new ToUpperCaseBehaviour());
  }
  /**
   * Try to determine as fast as possible if a redirect is necessary
   *
   * @param requestURI
   * @param contextPath
   * @return null, if no redirect is necessary. Else the redirect URL
   */
  protected final String checkIfRedirectRequired(
      final String requestURI, final String contextPath) {
    // length without jsessionid (http://.../abc;jsessionid=...?param)
    int uriLength = requestURI.indexOf(';');
    if (uriLength == -1) {
      uriLength = requestURI.length();
    }

    // request.getContextPath() + "/" + filterPath. But without any trailing "/".
    int homePathLength = contextPath.length() + (filterPathLength > 0 ? 1 + filterPathLength : 0);
    if (uriLength != homePathLength) {
      // requestURI and homePath are different (in length)
      // => continue with standard request processing. No redirect.
      return null;
    }

    // Fail fast failed. Revert to "slow" but exact check
    String uri = Strings.stripJSessionId(requestURI);

    // home page without trailing slash URI
    String homePageUri = contextPath + '/' + getFilterPath();
    if (homePageUri.endsWith("/")) {
      homePageUri = homePageUri.substring(0, homePageUri.length() - 1);
    }

    // If both are equal => redirect
    if (uri.equals(homePageUri)) {
      uri += "/";
      return uri;
    }

    // no match => standard request processing; no redirect
    return null;
  }
  /**
   * Returns a relative path to the filter path and context root from an HttpServletRequest - use
   * this to resolve a Wicket request.
   *
   * @param request
   * @return Path requested, minus query string, context path, and filterPath. Relative, no leading
   *     '/'.
   */
  public String getRelativePath(HttpServletRequest request) {
    String path = Strings.stripJSessionId(request.getRequestURI());
    String contextPath = request.getContextPath();
    path = path.substring(contextPath.length());
    if (isServlet) {
      String servletPath = request.getServletPath();
      path = path.substring(servletPath.length());
    }

    if (path.length() > 0) {
      path = path.substring(1);
    }

    // We should always be under the rootPath, except
    // for the special case of someone landing on the
    // home page without a trailing slash.
    String filterPath = getFilterPath();
    if (!path.startsWith(filterPath)) {
      if (filterPath.equals(path + "/")) {
        path += "/";
      }
    }
    if (path.startsWith(filterPath)) {
      path = path.substring(filterPath.length());
    }

    return path;
  }
Exemple #9
0
  /**
   * Strip any jsessionid and possibly other redundant info that might be in our way.
   *
   * @param url The url to strip
   * @return The stripped url
   */
  public static String stripJSessionId(final String url) {
    if (Strings.isEmpty(url)) {
      return url;
    }

    // http://.../abc;jsessionid=...?param=...
    int ixSemiColon = url.toLowerCase(Locale.ENGLISH).indexOf(";jsessionid=");
    if (ixSemiColon == -1) {
      return url;
    }

    int ixQuestionMark = url.indexOf('?');
    if (ixQuestionMark == -1) {
      // no query paramaters; cut off at ";"
      // http://.../abc;jsession=...
      return url.substring(0, ixSemiColon);
    }

    if (ixQuestionMark <= ixSemiColon) {
      // ? is before ; - no jsessionid in the url
      return url;
    }

    return url.substring(0, ixSemiColon) + url.substring(ixQuestionMark);
  }
Exemple #10
0
 /**
  * Joins string fragments using the specified separator
  *
  * @param separator
  * @param fragments
  * @return combined fragments
  */
 public static String join(final String separator, final String... fragments) {
   if ((fragments == null) || (fragments.length < 1)) {
     // no elements
     return "";
   } else if (fragments.length < 2) {
     // single element
     return fragments[0];
   } else {
     // two or more elements
     StringBuilder buff = new StringBuilder(128);
     if (fragments[0] != null) {
       buff.append(fragments[0]);
     }
     for (int i = 1; i < fragments.length; i++) {
       String fragment = fragments[i];
       if ((fragments[i - 1] != null) || (fragment != null)) {
         boolean lhsClosed = fragments[i - 1].endsWith(separator);
         boolean rhsClosed = fragment.startsWith(separator);
         if (lhsClosed && rhsClosed) {
           buff.append(fragment.substring(1));
         } else if (!lhsClosed && !rhsClosed) {
           if (!Strings.isEmpty(fragment)) {
             buff.append(separator);
           }
           buff.append(fragment);
         } else {
           buff.append(fragment);
         }
       }
     }
     return buff.toString();
   }
 }
Exemple #11
0
 /** @see org.apache.wicket.behavior.AbstractBehavior#onRendered(org.apache.wicket.Component) */
 public void onRendered(Component component) {
   super.onRendered(component);
   // Append the span and img icon right after the rendering of the
   // component. Not as pretty as working with a panel etc, but works
   // for behaviors and is more efficient
   Response response = component.getResponse();
   response.write("\n<span>&nbsp;<img style=\"");
   response.write(getIconStyle());
   response.write("\" id=\"");
   response.write(getIconId());
   response.write("\" src=\"");
   CharSequence iconUrl = getIconUrl();
   // displayCalendar(document.forms[0].theDate,'yyyy/mm/dd',this)
   response.write(Strings.escapeMarkup(iconUrl != null ? iconUrl.toString() : ""));
   response.write("\" onclick=\"displayCalendar(document.getElementById('");
   response.write(component.getMarkupId());
   response.write("'),'");
   String datePattern = getDatePattern().replaceAll("mm", "ii").toLowerCase();
   datePattern = datePattern.replace('s', '0'); // (mili)seconds are not supported
   response.write(datePattern);
   if (datePattern.indexOf("h") == -1) {
     response.write("',this)\"");
   } else {
     response.write("',this,true)\"");
   }
   response.write(" /></span>");
 }
    @Override
    public void onRequest() {
      term =
          this.getComponent()
              .getRequest()
              .getQueryParameters()
              .getParameterValue("term")
              .toString();

      if (!Strings.isEmpty(term)) {
        StringWriter sw = new StringWriter();
        try {
          JsonGenerator gen = new JsonFactory().createJsonGenerator(sw);

          AutocompleteJson value = null;
          Integer index = 0;
          List<Object> json = new ArrayList<Object>();

          for (T obj : getValues(term)) {
            index++;
            value = newAutocompleteJson(index, obj);
            json.add(value);
          }

          new ObjectMapper().writeValue(gen, json);

        } catch (IOException e) {
          throw new WicketRuntimeException(e);
        }

        RequestCycle.get()
            .scheduleRequestHandlerAfterCurrent(
                new TextRequestHandler("application/json", "utf-8", sw.toString()));
      }
    }
  @Override
  public void onConfigure(JQueryBehavior behavior) {
    super.onConfigure(behavior);

    StringBuilder statements = new StringBuilder();

    statements
        .append("jQuery('#")
        .append(this.lower.getMarkupId())
        .append("').val(ui.values[0]); ");
    statements
        .append("jQuery('#")
        .append(this.upper.getMarkupId())
        .append("').val(ui.values[1]); ");

    if (!Strings.isEmpty(super.labelId)) {
      statements
          .append("jQuery('#")
          .append(super.labelId)
          .append("').text(")
          .append(this.getLabelPattern())
          .append("); ");
    }

    behavior.setOption("slide", String.format("function(event, ui) { %s }", statements));
    behavior.setOption("values", this.getModelObject());
  }
  /** {@inheritDoc} */
  public void onResourceRequested() {
    final String fileName =
        RequestCycle.get()
            .getRequest()
            .getQueryParameters()
            .getParameterValue(ImageUploadHelper.IMAGE_FILE_NAME)
            .toString();
    if (Strings.isEmpty(fileName)) {
      log.warn("There is no file name of image");
      return;
    }
    final String contentType =
        RequestCycle.get()
            .getRequest()
            .getQueryParameters()
            .getParameterValue(ImageUploadHelper.IMAGE_CONTENT_TYPE)
            .toString();

    FileInputStream inputStream = null;
    try {
      inputStream = new FileInputStream(uploadFolderPath + File.separatorChar + fileName);
    } catch (FileNotFoundException ex) {
      log.error("Problem with getting image - " + ex.getMessage(), ex);
      throw new RuntimeException("Problem with getting image");
    }
    RequestCycle.get()
        .scheduleRequestHandlerAfterCurrent(
            new ResourceStreamRequestHandler(new FileResourceStream(contentType, inputStream)));
  }
Exemple #15
0
 public static SupportedMedia resolveFromMimeType(String mimeType) {
   if (Strings.isEmpty(mimeType)) return null;
   for (SupportedMedia supportedMedia : SupportedMedia.values()) {
     if (StringUtils.equalsIgnoreCase(supportedMedia.getMimeType(), mimeType)) {
       return supportedMedia;
     }
   }
   return null;
 }
 public ExtensionResourceNameIterator(final String extension, final char separatorChar) {
   super();
   String[] extensions = Strings.split(extension, separatorChar);
   if (extensions.length == 0) {
     extensions = new String[] {""};
   }
   this.extensions = extensions;
   this.index = 0;
 }
  /**
   * Returns the name of the Bean as registered to Spring. Throws IllegalState exception if none or
   * more than one beans are found.
   *
   * @param ctx spring application context
   * @param clazz bean class
   * @param required true if the value is required
   * @throws IllegalStateException
   * @return spring name of the bean
   */
  private String getBeanNameOfClass(
      final ApplicationContext ctx, final Class<?> clazz, final boolean required) {
    // get the list of all possible matching beans
    List<String> names =
        new ArrayList<String>(
            Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(ctx, clazz)));

    // filter out beans that are not candidates for autowiring
    if (ctx instanceof AbstractApplicationContext) {
      Iterator<String> it = names.iterator();
      while (it.hasNext()) {
        final String possibility = it.next();
        BeanDefinition beanDef =
            getBeanDefinition(((AbstractApplicationContext) ctx).getBeanFactory(), possibility);
        if (BeanFactoryUtils.isFactoryDereference(possibility)
            || possibility.startsWith("scopedTarget.")
            || (beanDef != null && !beanDef.isAutowireCandidate())) {
          it.remove();
        }
      }
    }

    if (names.isEmpty()) {
      if (required) {
        throw new IllegalStateException("bean of type [" + clazz.getName() + "] not found");
      }
      return null;
    } else if (names.size() > 1) {
      if (ctx instanceof AbstractApplicationContext) {
        List<String> primaries = new ArrayList<String>();
        for (String name : names) {
          BeanDefinition beanDef =
              getBeanDefinition(((AbstractApplicationContext) ctx).getBeanFactory(), name);
          if (beanDef instanceof AbstractBeanDefinition) {
            if (beanDef.isPrimary()) {
              primaries.add(name);
            }
          }
        }
        if (primaries.size() == 1) {
          return primaries.get(0);
        }
      }
      StringBuilder msg = new StringBuilder();
      msg.append("More than one bean of type [");
      msg.append(clazz.getName());
      msg.append("] found, you have to specify the name of the bean ");
      msg.append(
          "(@SpringBean(name=\"foo\")) or (@Named(\"foo\") if using @javax.inject classes) in order to resolve this conflict. ");
      msg.append("Matched beans: ");
      msg.append(Strings.join(",", names.toArray(new String[names.size()])));
      throw new IllegalStateException(msg.toString());
    } else {
      return names.get(0);
    }
  }
Exemple #18
0
 public static SupportedMedia resolveFromPath(String media) {
   if (Strings.isEmpty(media)) return null;
   String[] splits = Strings.split(media, '|');
   if (splits.length == 1) {
     String[] fileNameSplits = Strings.split(splits[0], '.');
     String ext = fileNameSplits.length == 2 ? fileNameSplits[1] : null;
     if (ext != null) {
       for (SupportedMedia supportedMedia : SupportedMedia.values()) {
         if (supportedMedia.getExtensions() != null) {
           for (String e : supportedMedia.getExtensions()) {
             if (StringUtils.equalsIgnoreCase(e, ext)) return supportedMedia;
           }
         }
       }
     }
     return null;
   }
   return resolveFromMimeType(splits[1]);
 }
 protected void encodePageComponentInfo(Url url, PageComponentInfo info) {
   Args.notNull(url, "url");
   if (info != null && Session.exists() && !Session.get().isSessionInvalidated()) {
     String s = info.toString();
     if (!Strings.isEmpty(s)) {
       QueryParameter parameter = new QueryParameter(s, "");
       url.getQueryParameters().add(parameter);
     }
   }
 }
Exemple #20
0
  /**
   * Constructeur
   *
   * @param name Name of the cookie
   */
  public JQueryCookieOption(String name) {
    super();

    if (Strings.isEmpty(name)) {
      throw new WicketRuntimeException("name cannot be null or empty");
    }

    options = new Options();
    setName(name);
  }
  /**
   * Appends specified {@code value} to the attribute
   *
   * @param key The key
   * @param value The value
   * @param separator The separator used to append the value
   */
  public final void append(String key, CharSequence value, String separator) {
    String current = getAttribute(key);
    if (Strings.isEmpty(current)) {
      xmlTag.put(key, value);
    } else {
      xmlTag.put(key, current + separator + value);
    }

    setModified(true);
  }
Exemple #22
0
  private Url decryptUrl(final Request request, final Url encryptedUrl) {
    if (encryptedUrl.getSegments().isEmpty()) {
      return encryptedUrl;
    }

    List<String> encryptedSegments = encryptedUrl.getSegments();
    if (encryptedSegments.size() < 1) {
      return null;
    }

    Url url = new Url(request.getCharset());
    try {
      String encryptedUrlString = encryptedSegments.get(0);
      if (Strings.isEmpty(encryptedUrlString)) {
        return null;
      }

      String decryptedUrl = getCrypt().decryptUrlSafe(encryptedUrlString);
      if (decryptedUrl == null) {
        return null;
      }
      Url originalUrl = Url.parse(decryptedUrl, request.getCharset());

      int originalNumberOfSegments = originalUrl.getSegments().size();
      int encryptedNumberOfSegments = encryptedUrl.getSegments().size();

      HashedSegmentGenerator generator = new HashedSegmentGenerator(encryptedUrlString);
      int segNo = 1;
      for (; segNo < encryptedNumberOfSegments; segNo++) {
        if (segNo > originalNumberOfSegments) {
          break;
        }

        String next = generator.next();
        String encryptedSegment = encryptedSegments.get(segNo);
        if (!next.equals(encryptedSegment)) {
          break;
        }

        // unmodified segment
        url.getSegments().add(originalUrl.getSegments().get(segNo - 1));
      }
      for (; segNo < encryptedNumberOfSegments; segNo++) {
        // modified or additional segment
        url.getSegments().add(encryptedUrl.getSegments().get(segNo));
      }

      url.getQueryParameters().addAll(originalUrl.getQueryParameters());
    } catch (Exception e) {
      log.error("Error decrypting URL", e);
      url = null;
    }

    return url;
  }
 private void writeMessages(Component component, Response response) {
   //
   // Note how bootstrap cannot have separate markup
   // for error/info messages attached to the same field.
   //
   for (FeedbackMessage message : collectMessages(component)) {
     response.write("<span class=\"help-block\">");
     response.write(Strings.escapeMarkup(message.getMessage().toString()));
     response.write("</span>");
   }
 }
 /**
  * Get the absolute bookmarkable path of a page
  *
  * @param pageClass Page
  * @param pageParameters Optional page parameters
  * @return Bookmarkable path
  */
 public static String absoluteMountPathForPage(
     Class<? extends Page> pageClass, PageParameters pageParameters) {
   HttpServletRequest req = getHttpServletRequest();
   RequestCycle requestCycle = RequestCycle.get();
   Url url = requestCycle.mapUrlFor(pageClass, pageParameters);
   String renderedUrl = url.toString();
   renderedUrl = Strings.isEmpty(renderedUrl) ? "." : renderedUrl;
   return RequestUtils.toAbsolutePath(
       HttpUtils.getWebappContextUrl(req),
       requestCycle.getOriginalResponse().encodeURL(renderedUrl));
 }
 private void writeLabel(FormComponent<?> fc, Response response) {
   final IModel<String> labelModel = fc.getLabel();
   if (labelModel != null) {
     String markupId = fc.getMarkupId();
     response.write("<label class=\"control-label\" for=\"" + markupId + "\">");
     response.write(Strings.escapeMarkup(labelModel.getObject()));
     if (fc.isRequired() && fc.isEnabled()) {
       response.write(REQUIRED_STAR);
     }
     response.write("</label>");
   }
 }
  /**
   * @see
   *     org.apache.wicket.resource.loader.ComponentStringResourceLoader#loadStringResource(java.lang.Class,
   *     java.lang.String, java.util.Locale, java.lang.String, java.lang.String)
   */
  @Override
  public String loadStringResource(
      Class<?> clazz,
      final String key,
      final Locale locale,
      final String style,
      final String variation) {
    if (clazz == null) {
      return null;
    }

    // Load the properties associated with the path
    IPropertiesFactory propertiesFactory = getPropertiesFactory();

    while (true) {
      Package pkg = clazz.getPackage();
      String packageName = (pkg == null) ? "" : pkg.getName();
      packageName = packageName.replace('.', '/');

      do {
        // Create the base path
        String path = filename;
        if (packageName.length() > 0) {
          path = packageName + "/" + path;
        }

        // Iterator over all the combinations
        IResourceNameIterator iter = newResourceNameIterator(path, locale, style, variation);
        while (iter.hasNext()) {
          String newPath = iter.next();

          Properties props = propertiesFactory.load(clazz, newPath);
          if (props != null) {
            // Lookup the value
            String value = props.getString(key);
            if (value != null) {
              return value;
            }
          }
        }

        // Didn't find the key yet, continue searching if possible
        packageName = Strings.beforeLast(packageName, '/');
      } while (packageName.length() > 0);

      clazz = clazz.getSuperclass();
      if (clazz == null) {
        break;
      }
    }
    // not found
    return null;
  }
Exemple #27
0
 /**
  * Write a reference to a javascript file to the response object
  *
  * @param response The HTTP response
  * @param url The javascript file URL
  * @param id Unique identifier of element
  * @param defer specifies that the execution of a script should be deferred (delayed) until after
  *     the page has been loaded.
  * @param charset a non null value specifies the charset attribute of the script tag
  */
 public static void writeJavaScriptUrl(
     final Response response,
     final CharSequence url,
     final String id,
     boolean defer,
     String charset) {
   response.write("<script type=\"text/javascript\" ");
   if (id != null) {
     response.write("id=\"" + Strings.escapeMarkup(id) + "\" ");
   }
   if (defer) {
     response.write("defer=\"defer\" ");
   }
   if (charset != null) {
     response.write("charset=\"" + Strings.escapeMarkup(charset) + "\" ");
   }
   response.write("src=\"");
   response.write(Strings.escapeMarkup(url));
   response.write("\"></script>");
   response.write("\n");
 }
  @Override
  public CalendarMonth convertToObject(String value, Locale locale) {
    if (Strings.isEmpty(value)) {
      return null;
    }

    try {
      return CalendarMonth.parse(value, datePattern);
    } catch (ParseException e) {
      throw newConversionException(
          "Cannot convert '" + value + "' to CalendarMonth", value, locale);
    }
  }
 /**
  * Convert the input respecting the flag convertEmptyInputStringToNull. Subclasses that override
  * this method should test this flag also.
  *
  * @see org.apache.wicket.markup.html.form.FormComponent#convertInput()
  */
 @Override
 protected void convertInput() {
   // Stateless forms don't have to be rendered first, convertInput could be called before
   // onBeforeRender calling resolve type here again to check if the type is correctly set.
   resolveType();
   String[] value = getInputAsArray();
   String tmp = value != null && value.length > 0 ? value[0] : null;
   if (getConvertEmptyInputStringToNull() && Strings.isEmpty(tmp)) {
     setConvertedInput(null);
   } else {
     super.convertInput();
   }
 }
  @Override
  public Component resolve(
      final MarkupContainer container, final MarkupStream markupStream, final ComponentTag tag) {
    String inlineEnclosureChildId = getAttribute(tag, markupStream);
    if (Strings.isEmpty(inlineEnclosureChildId) == false) {
      String id = tag.getId();

      // Yes, we handled the tag
      return new InlineEnclosure(id, inlineEnclosureChildId);
    }

    // We were not able to handle the tag
    return null;
  }