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
020package org.apache.isis.core.progmodel.facets.object.parseable;
021
022import java.util.IllegalFormatException;
023
024import org.apache.isis.applib.adapters.Parser;
025import org.apache.isis.applib.adapters.ParsingException;
026import org.apache.isis.applib.profiles.Localization;
027import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
028import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
029import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
030import org.apache.isis.core.metamodel.adapter.util.AdapterUtils;
031import org.apache.isis.core.metamodel.consent.InteractionInvocationMethod;
032import org.apache.isis.core.metamodel.consent.InteractionResultSet;
033import org.apache.isis.core.metamodel.deployment.DeploymentCategory;
034import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
035import org.apache.isis.core.metamodel.facetapi.FacetHolder;
036import org.apache.isis.core.metamodel.facets.object.parseable.ParseableFacet;
037import org.apache.isis.core.metamodel.facets.object.parseable.TextEntryParseException;
038import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
039import org.apache.isis.core.metamodel.interactions.InteractionUtils;
040import org.apache.isis.core.metamodel.interactions.ObjectValidityContext;
041import org.apache.isis.core.metamodel.interactions.ParseValueContext;
042import org.apache.isis.core.metamodel.interactions.ValidityContext;
043import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
044import org.apache.isis.core.metamodel.spec.ObjectSpecification;
045
046public class ParseableFacetUsingParser extends FacetAbstract implements ParseableFacet {
047
048    private final Parser<?> parser;
049    private final DeploymentCategory deploymentCategory;
050    private final AuthenticationSessionProvider authenticationSessionProvider;
051    private final ServicesInjector dependencyInjector;
052    private final AdapterManager adapterManager;
053
054    public ParseableFacetUsingParser(
055            final Parser<?> parser, final FacetHolder holder, 
056            final DeploymentCategory deploymentCategory, final AuthenticationSessionProvider authenticationSessionProvider, final ServicesInjector dependencyInjector, final AdapterManager adapterManager) {
057        super(ParseableFacet.class, holder, Derivation.NOT_DERIVED);
058        this.parser = parser;
059        this.deploymentCategory = deploymentCategory;
060        this.authenticationSessionProvider = authenticationSessionProvider;
061        this.dependencyInjector = dependencyInjector;
062        this.adapterManager = adapterManager;
063    }
064
065    @Override
066    protected String toStringValues() {
067        dependencyInjector.injectServicesInto(parser);
068        return parser.toString();
069    }
070
071    @Override
072    public ObjectAdapter parseTextEntry(final ObjectAdapter contextAdapter, final String entry, Localization localization) {
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 = getAdapterManager().adapterFor(entry);
081            final ParseValueContext parseValueContext = new ParseValueContext(deploymentCategory, getAuthenticationSessionProvider().getAuthenticationSession(), InteractionInvocationMethod.BY_USER, contextAdapter, getIdentified().getIdentifier(), entryAdapter);
082            validate(parseValueContext);
083        }
084
085        final Object context = AdapterUtils.unwrap(contextAdapter);
086
087        getDependencyInjector().injectServicesInto(parser);
088
089        try {
090            final Object parsed = parser.parseTextEntry(context, entry, localization);
091            if (parsed == null) {
092                return null;
093            }
094
095            // check resultant object is also valid
096            // (eg pick up any validate() methods on it)
097            final ObjectAdapter adapter = getAdapterManager().adapterFor(parsed);
098            final ObjectSpecification specification = adapter.getSpecification();
099            final ObjectValidityContext validateContext = specification.createValidityInteractionContext(deploymentCategory, getAuthenticationSessionProvider().getAuthenticationSession(), InteractionInvocationMethod.BY_USER, adapter);
100            validate(validateContext);
101
102            return adapter;
103        } catch (final NumberFormatException e) {
104            throw new TextEntryParseException(e.getMessage(), e);
105        } catch (final IllegalFormatException e) {
106            throw new TextEntryParseException(e.getMessage(), e);
107        } catch (final ParsingException e) {
108            throw new TextEntryParseException(e.getMessage(), e);
109        }
110    }
111
112    private void validate(final ValidityContext<?> validityContext) {
113        final InteractionResultSet resultSet = new InteractionResultSet();
114        InteractionUtils.isValidResultSet(getFacetHolder(), validityContext, resultSet);
115        if (resultSet.isVetoed()) {
116            throw new IllegalArgumentException(resultSet.getInteractionResult().getReason());
117        }
118    }
119
120    /**
121     * TODO: need to fix genericity of using Parser<?>, for now suppressing
122     * warnings.
123     */
124    @Override
125    @SuppressWarnings({ "unchecked", "rawtypes" })
126    public String parseableTitle(final ObjectAdapter contextAdapter) {
127        final Object pojo = AdapterUtils.unwrap(contextAdapter);
128
129        getDependencyInjector().injectServicesInto(parser);
130        return ((Parser)parser).parseableTitleOf(pojo);
131    }
132
133    // /////////////////////////////////////////////////////////
134    // Dependencies (from constructor)
135    // /////////////////////////////////////////////////////////
136
137    /**
138     * @return the dependencyInjector
139     */
140    public ServicesInjector 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 AdapterManager getAdapterManager() {
155        return adapterManager;
156    }
157}