Beispiel #1
0
 private static GroovyObject lookupCachedTagLib(
     GrailsWebRequest webRequest,
     TagLibraryLookup gspTagLibraryLookup,
     String namespace,
     String tagName) {
   if (webRequest != null) {
     // caches the taglibs in request context. is this a good idea or not?
     String tagKey = namespace + ":" + tagName;
     Map<String, GroovyObject> tagLibCache =
         (Map<String, GroovyObject>)
             webRequest.getCurrentRequest().getAttribute(REQUEST_TAGLIB_CACHE);
     GroovyObject tagLib = null;
     if (tagLibCache == null) {
       tagLibCache = new HashMap<String, GroovyObject>();
       webRequest.getCurrentRequest().setAttribute(REQUEST_TAGLIB_CACHE, tagLibCache);
     } else {
       tagLib = tagLibCache.get(tagKey);
     }
     if (tagLib == null) {
       tagLib = gspTagLibraryLookup.lookupTagLibrary(namespace, tagName);
       if (tagLib != null) {
         tagLibCache.put(tagKey, tagLib);
       }
     }
     return tagLib;
   } else {
     return gspTagLibraryLookup != null
         ? gspTagLibraryLookup.lookupTagLibrary(namespace, tagName)
         : null;
   }
 }
  /**
   * Looks up namespaces on missing property
   *
   * @param instance The instance
   * @param propertyName The property name
   * @return The namespace or a MissingPropertyException
   */
  public Object propertyMissing(Object instance, String propertyName) {
    TagLibraryLookup lookup = getTagLibraryLookup();
    NamespacedTagDispatcher namespacedTagDispatcher =
        lookup.lookupNamespaceDispatcher(propertyName);
    if (namespacedTagDispatcher != null) {
      if (!developmentMode) {
        WebMetaUtils.registerPropertyMissingForTag(
            GrailsMetaClassUtils.getMetaClass(instance), propertyName, namespacedTagDispatcher);
      }
      return namespacedTagDispatcher;
    }

    throw new MissingPropertyException(propertyName, instance.getClass());
  }
  /**
   * Method missing implementation that handles tag invocation by method name
   *
   * @param instance The instance
   * @param methodName The method name
   * @param argsObject The arguments
   * @return The result
   */
  public Object methodMissing(Object instance, String methodName, Object argsObject) {
    Object[] args =
        argsObject instanceof Object[] ? (Object[]) argsObject : new Object[] {argsObject};
    TagLibraryLookup lookup = getTagLibraryLookup();
    if (lookup != null) {
      GroovyObject tagLibrary = lookup.lookupTagLibrary(GroovyPage.DEFAULT_NAMESPACE, methodName);
      if (tagLibrary != null) {
        if (!developmentMode) {
          MetaClass controllerMc = GrailsMetaClassUtils.getMetaClass(instance);
          WebMetaUtils.registerMethodMissingForTags(
              controllerMc, lookup, GroovyPage.DEFAULT_NAMESPACE, methodName);
        }
        List<MetaMethod> respondsTo =
            tagLibrary.getMetaClass().respondsTo(tagLibrary, methodName, args);
        if (respondsTo.size() > 0) {
          return respondsTo.get(0).invoke(tagLibrary, args);
        }
      }
    }

    throw new MissingMethodException(methodName, instance.getClass(), args);
  }
Beispiel #4
0
  public Object getProperty(String property) {
    if (OUT.equals(property)) return out;
    // in GSP we assume if a property doesn't exist that
    // it is null rather than throw an error this works nicely
    // with the Groovy Truth
    if (BINDING.equals(property)) return getBinding();

    Object value = getBinding().getVariables().get(property);
    if (value != null) {
      return value;
    }

    if (value == null) {
      MetaProperty mp = getMetaClass().getMetaProperty(property);
      if (mp != null) {
        return mp.getProperty(this);
      }
    }

    if (value == null) {
      value =
          gspTagLibraryLookup != null
              ? gspTagLibraryLookup.lookupNamespaceDispatcher(property)
              : null;
      if (value == null && jspTags.containsKey(property)) {
        TagLibraryResolver tagResolver = getTagLibraryResolver();

        String uri = (String) jspTags.get(property);
        if (uri != null) value = tagResolver.resolveTagLibrary(uri);
      }
      if (value != null) {
        // cache lookup for next execution
        getBinding().setVariable(property, value);
      }
    }

    return value;
  }
Beispiel #5
0
  public static Object captureTagOutput(
      TagLibraryLookup gspTagLibraryLookup,
      String namespace,
      String tagName,
      Map attrs,
      Object body,
      GrailsWebRequest webRequest) {
    if (!(attrs instanceof GroovyPageAttributes)) {
      attrs = new GroovyPageAttributes(attrs);
    }
    GroovyObject tagLib = lookupCachedTagLib(webRequest, gspTagLibraryLookup, namespace, tagName);

    boolean preferSubChunkWhenWritingToOtherBuffer = resolvePreferSubChunk(namespace, tagName);
    Closure actualBody =
        createOutputCapturingClosure(
            tagLib, body, webRequest, preferSubChunkWhenWritingToOtherBuffer);

    final GroovyPageTagWriter out = new GroovyPageTagWriter(preferSubChunkWhenWritingToOtherBuffer);
    try {
      GroovyPageOutputStack.currentStack().push(out);
      Object tagLibProp = tagLib.getProperty(tagName); // retrieve tag lib and create wrapper writer
      if (tagLibProp instanceof Closure) {
        Closure tag = (Closure) ((Closure) tagLibProp).clone();
        Object bodyResult = null;

        if (tag.getParameterTypes().length == 1) {
          bodyResult = tag.call(new Object[] {attrs});
          if (actualBody != null && actualBody != EMPTY_BODY_CLOSURE) {
            Object bodyResult2 = actualBody.call();
            if (bodyResult2 != null) {
              out.print(bodyResult2);
            }
          }
        } else if (tag.getParameterTypes().length == 2) {
          bodyResult = tag.call(new Object[] {attrs, actualBody});
        } else {
          throw new GrailsTagException(
              "Tag ["
                  + tagName
                  + "] does not specify expected number of params in tag library ["
                  + tagLib.getClass().getName()
                  + "]");
        }

        boolean returnsObject = gspTagLibraryLookup.doesTagReturnObject(namespace, tagName);

        if (returnsObject && bodyResult != null && !(bodyResult instanceof Writer)) {
          return bodyResult;
        }
        // add some method to always return string, configurable?
        return out.getBuffer();
      } else {
        throw new GrailsTagException(
            "Tag ["
                + tagName
                + "] does not exist in tag library ["
                + tagLib.getClass().getName()
                + "]");
      }
    } finally {
      GroovyPageOutputStack.currentStack().pop();
    }
  }
Beispiel #6
0
  public void invokeTag(
      String tagName, String tagNamespace, int lineNumber, Map attrs, Closure body) {
    // TODO custom namespace stuff needs to be generalized and pluggable
    if (tagNamespace.equals(TEMPLATE_NAMESPACE)) {
      final String tmpTagName = tagName;
      final Map tmpAttrs = attrs;
      tagName = "render";
      tagNamespace = DEFAULT_NAMESPACE;
      attrs =
          new HashMap() {
            {
              put("model", tmpAttrs);
              put("template", tmpTagName);
            }
          };
    } else if (tagNamespace.equals(LINK_NAMESPACE)) {
      final String tmpTagName = tagName;
      final Map tmpAttrs = attrs;
      tagName = "link";
      tagNamespace = DEFAULT_NAMESPACE;
      attrs =
          new HashMap() {
            {
              if (tmpAttrs.size() > 0) {
                put("params", tmpAttrs);
              }
              put("mapping", tmpTagName);
            }
          };
    }

    try {
      GroovyObject tagLib = getTagLib(tagNamespace, tagName);
      if (tagLib != null || gspTagLibraryLookup.hasNamespace(tagNamespace)) {
        if (tagLib != null) {
          boolean returnsObject = gspTagLibraryLookup.doesTagReturnObject(tagNamespace, tagName);
          Object tagLibProp = tagLib.getProperty(tagName);
          if (tagLibProp instanceof Closure) {
            Closure tag = (Closure) ((Closure) tagLibProp).clone();
            Object tagresult = null;

            // GSP<->Sitemesh integration requires that the body or head subchunk isn't written to
            // output
            boolean preferSubChunkWhenWritingToOtherBuffer =
                resolvePreferSubChunk(tagNamespace, tagName);
            if (body instanceof GroovyPageTagBody && preferSubChunkWhenWritingToOtherBuffer) {
              ((GroovyPageTagBody) body).setPreferSubChunkWhenWritingToOtherBuffer(true);
            }

            switch (tag.getParameterTypes().length) {
              case 1:
                tagresult = tag.call(new Object[] {attrs});
                if (returnsObject && tagresult != null && !(tagresult instanceof Writer)) {
                  out.print(tagresult);
                }
                if (body != null && body != EMPTY_BODY_CLOSURE) {
                  body.call();
                }

                break;

              case 2:
                if (tag.getParameterTypes().length == 2) {
                  tagresult =
                      tag.call(new Object[] {attrs, (body != null) ? body : EMPTY_BODY_CLOSURE});
                  if (returnsObject && tagresult != null && !(tagresult instanceof Writer)) {
                    out.print(tagresult);
                  }
                }
                break;
            }

          } else {
            throw new GrailsTagException(
                "Tag ["
                    + tagName
                    + "] does not exist in tag library ["
                    + tagLib.getClass().getName()
                    + "]",
                getGroovyPageFileName(),
                lineNumber);
          }
        } else {
          throw new GrailsTagException(
              "Tag ["
                  + tagName
                  + "] does not exist. No tag library found for namespace: "
                  + tagNamespace,
              getGroovyPageFileName(),
              lineNumber);
        }
      } else {
        out.append('<').append(tagNamespace).append(':').append(tagName);
        for (Object o : attrs.entrySet()) {
          Map.Entry entry = (Map.Entry) o;
          out.append(' ');
          out.append(entry.getKey()).append('=');
          String value = String.valueOf(entry.getValue());
          // handle attribute value quotes & possible escaping " -> &quot;
          boolean containsQuotes = (value.indexOf('"') > -1);
          boolean containsSingleQuote = (value.indexOf('\'') > -1);
          if (containsQuotes && !containsSingleQuote) {
            out.append('\'').append(value).append('\'');
          } else if (containsQuotes & containsSingleQuote) {
            out.append('\"').append(value.replaceAll("\"", "&quot;")).append('\"');
          } else {
            out.append('\"').append(value).append('\"');
          }
        }
        out.append('>');
        if (body != null) {
          Object bodyOutput = body.call();
          if (bodyOutput != null) out.print(bodyOutput);
        }
        out.append("</").append(tagNamespace).append(':').append(tagName).append('>');
      }
    } catch (Throwable e) {
      if (LOG.isTraceEnabled()) {
        LOG.trace("Full exception for problem at " + getGroovyPageFileName() + ":" + lineNumber, e);
      }

      // The capture* tags are internal tags and not to be displayed to the user
      // hence we don't wrap the exception and simple rethrow it
      if (tagName.matches("capture(Body|Head|Meta|Title|Component)")) {
        RuntimeException rte = GrailsExceptionResolver.getFirstRuntimeException(e);
        if (rte == null) {
          throwRootCause(tagName, tagNamespace, lineNumber, e);
        } else {
          throw rte;
        }
      } else {
        throwRootCause(tagName, tagNamespace, lineNumber, e);
      }
    }
  }