001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *
010     *        http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License.
018     */
019    
020    package org.apache.isis.core.progmodel.facets.object.parseable;
021    
022    import java.util.IllegalFormatException;
023    
024    import org.apache.isis.applib.adapters.Parser;
025    import org.apache.isis.applib.adapters.ParsingException;
026    import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
027    import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
028    import org.apache.isis.core.metamodel.adapter.map.AdapterMap;
029    import org.apache.isis.core.metamodel.adapter.util.AdapterUtils;
030    import org.apache.isis.core.metamodel.consent.InteractionInvocationMethod;
031    import org.apache.isis.core.metamodel.consent.InteractionResultSet;
032    import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
033    import org.apache.isis.core.metamodel.facetapi.FacetHolder;
034    import org.apache.isis.core.metamodel.facets.object.parseable.ParseableFacet;
035    import org.apache.isis.core.metamodel.facets.object.parseable.TextEntryParseException;
036    import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
037    import org.apache.isis.core.metamodel.interactions.InteractionUtils;
038    import org.apache.isis.core.metamodel.interactions.ObjectValidityContext;
039    import org.apache.isis.core.metamodel.interactions.ParseValueContext;
040    import org.apache.isis.core.metamodel.interactions.ValidityContext;
041    import org.apache.isis.core.metamodel.runtimecontext.DependencyInjector;
042    import org.apache.isis.core.metamodel.spec.ObjectSpecification;
043    
044    /**
045     * TODO: need to fix genericity of using Parser<?>, for now suppressing warnings.
046     */
047    public class ParseableFacetUsingParser extends FacetAbstract implements ParseableFacet {
048    
049        @SuppressWarnings("unchecked")
050        private final Parser parser;
051        private final DependencyInjector dependencyInjector;
052        private final AdapterMap adapterMap;
053        private final AuthenticationSessionProvider authenticationSessionProvider;
054    
055        public ParseableFacetUsingParser(@SuppressWarnings("unchecked") final Parser parser, final FacetHolder holder,
056            final AuthenticationSessionProvider authenticationSessionProvider, final DependencyInjector dependencyInjector,
057            final AdapterMap adapterManager) {
058            super(ParseableFacet.class, holder, false);
059            this.parser = parser;
060            this.authenticationSessionProvider = authenticationSessionProvider;
061            this.dependencyInjector = dependencyInjector;
062            this.adapterMap = adapterManager;
063        }
064    
065        @Override
066        protected String toStringValues() {
067            dependencyInjector.injectDependenciesInto(parser);
068            return parser.toString();
069        }
070    
071        @Override
072        public ObjectAdapter parseTextEntry(final ObjectAdapter contextAdapter, final String entry) {
073            if (entry == null) {
074                throw new IllegalArgumentException("An entry must be provided");
075            }
076    
077            // check string is valid
078            // (eg pick up any @RegEx on value type)
079            if (getFacetHolder().containsFacet(ValueFacet.class)) {
080                final ObjectAdapter entryAdapter = getAdapterMap().adapterFor(entry);
081                final ParseValueContext parseValueContext =
082                    new ParseValueContext(getAuthenticationSessionProvider().getAuthenticationSession(),
083                        InteractionInvocationMethod.BY_USER, contextAdapter, getIdentified().getIdentifier(), entryAdapter);
084                validate(parseValueContext);
085            }
086    
087            final Object context = AdapterUtils.unwrap(contextAdapter);
088    
089            getDependencyInjector().injectDependenciesInto(parser);
090    
091            try {
092                final Object parsed = parser.parseTextEntry(context, entry);
093                if (parsed == null) {
094                    return null;
095                }
096    
097                // check resultant object is also valid
098                // (eg pick up any validate() methods on it)
099                final ObjectAdapter adapter = getAdapterMap().adapterFor(parsed);
100                final ObjectSpecification specification = adapter.getSpecification();
101                final ObjectValidityContext validateContext =
102                    specification.createValidityInteractionContext(getAuthenticationSessionProvider()
103                        .getAuthenticationSession(), InteractionInvocationMethod.BY_USER, adapter);
104                validate(validateContext);
105    
106                return adapter;
107            } catch (final NumberFormatException e) {
108                throw new TextEntryParseException(e.getMessage(), e);
109            } catch (final IllegalFormatException e) {
110                throw new TextEntryParseException(e.getMessage(), e);
111            } catch (final ParsingException e) {
112                throw new TextEntryParseException(e.getMessage(), e);
113            }
114        }
115    
116        private void validate(final ValidityContext<?> validityContext) {
117            final InteractionResultSet resultSet = new InteractionResultSet();
118            InteractionUtils.isValidResultSet(getFacetHolder(), validityContext, resultSet);
119            if (resultSet.isVetoed()) {
120                throw new IllegalArgumentException(resultSet.getInteractionResult().getReason());
121            }
122        }
123    
124        @Override
125        @SuppressWarnings("unchecked")
126        public String parseableTitle(final ObjectAdapter contextAdapter) {
127            final Object pojo = AdapterUtils.unwrap(contextAdapter);
128    
129            getDependencyInjector().injectDependenciesInto(parser);
130            return parser.parseableTitleOf(pojo);
131        }
132    
133        // /////////////////////////////////////////////////////////
134        // Dependencies (from constructor)
135        // /////////////////////////////////////////////////////////
136    
137        /**
138         * @return the dependencyInjector
139         */
140        public DependencyInjector getDependencyInjector() {
141            return dependencyInjector;
142        }
143    
144        /**
145         * @return the authenticationSessionProvider
146         */
147        public AuthenticationSessionProvider getAuthenticationSessionProvider() {
148            return authenticationSessionProvider;
149        }
150    
151        /**
152         * @return the adapterManager
153         */
154        public AdapterMap getAdapterMap() {
155            return adapterMap;
156        }
157    }