    001    // Copyright 2006, 2007, 2008, 2009, 2010, 2011 The Apache Software Foundation
    002    //
    003    // Licensed under the Apache License, Version 2.0 (the "License");
    004    // you may not use this file except in compliance with the License.
    005    // You may obtain a copy of the License at
    006    //
    007    // http://www.apache.org/licenses/LICENSE-2.0
    008    //
    009    // Unless required by applicable law or agreed to in writing, software
    010    // distributed under the License is distributed on an "AS IS" BASIS,
    011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012    // See the License for the specific language governing permissions and
    013    // limitations under the License.
    014
    015    package org.apache.tapestry5.internal.services;
    016
    017    import org.apache.tapestry5.Binding;
    018    import org.apache.tapestry5.ComponentResources;
    019    import org.apache.tapestry5.ioc.Location;
    020    import org.apache.tapestry5.ioc.internal.util.InternalUtils;
    021    import org.apache.tapestry5.ioc.internal.util.TapestryException;
    022    import org.apache.tapestry5.services.BindingFactory;
    023    import org.apache.tapestry5.services.BindingSource;
    024
    025    import java.util.Map;
    026
    027    public class BindingSourceImpl implements BindingSource
    028    {
    029        private final Map<String, BindingFactory> factories;
    030
    031        private final StringInterner interner;
    032
    033        public BindingSourceImpl(Map<String, BindingFactory> factories, StringInterner interner)
    034        {
    035            this.factories = factories;
    036            this.interner = interner;
    037        }
    038
    039        public Binding newBinding(String description, ComponentResources container, String defaultPrefix, String expression)
    040        {
    041            return newBinding(description, container, container, defaultPrefix, expression, null);
    042        }
    043
    044        public Binding newBinding(String description, ComponentResources container, ComponentResources component,
    045                                  String defaultPrefix, String expression, Location location)
    046        {
    047            assert InternalUtils.isNonBlank(description);
    048            assert container != null;
    049            assert InternalUtils.isNonBlank(defaultPrefix);
    050            assert component != null;
    051
    052            // TAP5-845: The expression may be the empty string. This is ok, if it's compatible with
    053            // the default prefix (the empty string is not a valid property expression, but is valid
    054            // as a literal string, perhaps as an informal parameter).
    055
    056            // Location might be null
    057
    058            String subexpression = expression;
    059            int colonx = expression.indexOf(':');
    060
    061            BindingFactory factory = null;
    062
    063            if (colonx > 0)
    064            {
    065                String prefix = expression.substring(0, colonx);
    066
    067                factory = factories.get(prefix);
    068                if (factory != null)
    069                    subexpression = expression.substring(colonx + 1);
    070            }
    071
    072            if (factory == null)
    073                factory = factories.get(defaultPrefix);
    074
    075            // And if that's null, what then? We assume that the default prefix is a valid prefix,
    076            // or we'll get an NPE below and report it like any other error.
    077
    078            try
    079            {
    080                return factory.newBinding(interner.intern(description), container, component, subexpression, location);
    081            } catch (Exception ex)
    082            {
    083                throw new TapestryException(String.format("Could not convert '%s' into a component parameter binding: %s", expression, InternalUtils.toMessage(ex)), location, ex);
    084            }
    085        }
    086    }