001: /*
002: * Copyright 2004-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.springframework.webflow.core;
017:
018: import org.springframework.binding.expression.Expression;
019: import org.springframework.binding.expression.ExpressionParser;
020: import org.springframework.binding.expression.ParserException;
021: import org.springframework.binding.expression.SettableExpression;
022:
023: /**
024: * Static helper factory that creates instances of the default expression parser used by Spring Web Flow when requested.
025: * Marked final with a private constructor to prevent subclassing.
026: * <p>
027: * The default is an OGNL based expression parser. Also asserts that OGNL is in the classpath the first time the parser is used.
028: *
029: * @author Keith Donald
030: * @author Erwin Vervaet
031: */
032: public final class DefaultExpressionParserFactory {
033:
034: /**
035: * The singleton instance of the default expression parser.
036: */
037: private static ExpressionParser INSTANCE;
038:
039: // static factory - not instantiable
040: private DefaultExpressionParserFactory() {
041: }
042:
043: /**
044: * Returns the default expression parser. The returned expression parser is a thread-safe object.
045: * @return the expression parser
046: */
047: public static synchronized ExpressionParser getExpressionParser() {
048: // return a wrapper that will lazily load the default expression parser
049: // this prevents the default OGNL-based parser from being intialized until it is actually used
050: // which allows OGNL to be an optional dependency if the expression parser wrapper is replaced and never used
051: return new ExpressionParser() {
052: public boolean isDelimitedExpression(String expressionString) {
053: return getDefaultExpressionParser()
054: .isDelimitedExpression(expressionString);
055: }
056:
057: public Expression parseExpression(String expressionString)
058: throws ParserException {
059: return getDefaultExpressionParser().parseExpression(
060: expressionString);
061: }
062:
063: public SettableExpression parseSettableExpression(
064: String expressionString) throws ParserException,
065: UnsupportedOperationException {
066: return getDefaultExpressionParser()
067: .parseSettableExpression(expressionString);
068: }
069: };
070: }
071:
072: /**
073: * Returns the default expression parser, creating it if necessary.
074: * @return the default expression parser
075: */
076: private static synchronized ExpressionParser getDefaultExpressionParser() {
077: if (INSTANCE == null) {
078: INSTANCE = createDefaultExpressionParser();
079: }
080: return INSTANCE;
081: }
082:
083: /**
084: * Create the default expression parser.
085: * @return the default expression parser
086: */
087: private static ExpressionParser createDefaultExpressionParser() {
088: try {
089: Class.forName("ognl.Ognl");
090: return new WebFlowOgnlExpressionParser();
091: } catch (ClassNotFoundException e) {
092: throw new IllegalStateException(
093: "Unable to load the default expression parser: OGNL could not be found in the classpath. "
094: + "Please add OGNL 2.x to your classpath or set the default ExpressionParser instance to something that is in the classpath. "
095: + "Details: " + e.getMessage());
096: } catch (NoClassDefFoundError e) {
097: throw new IllegalStateException(
098: "Unable to construct the default expression parser: ognl.Ognl could not be instantiated. "
099: + "Please add OGNL 2.x to your classpath or set the default ExpressionParser instance to something that is in the classpath. "
100: + "Details: " + e);
101: }
102: }
103: }
|