All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jodd.madvoc.component.ResultsManager Maven / Gradle / Ivy

There is a newer version: 5.1.0-20190624
Show newest version
// Copyright (c) 2003-present, Jodd Team (http://jodd.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

package jodd.madvoc.component;

import jodd.log.Logger;
import jodd.log.LoggerFactory;
import jodd.madvoc.ActionConfig;
import jodd.madvoc.ActionRequest;
import jodd.madvoc.MadvocException;
import jodd.madvoc.injector.Target;
import jodd.madvoc.meta.RenderWith;
import jodd.madvoc.result.ActionResult;
import jodd.madvoc.result.Result;
import jodd.petite.meta.PetiteInject;
import jodd.typeconverter.TypeConverterManager;

import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;

/**
 * Manager for Madvoc result handlers.
 */
public class ResultsManager {

	private static final Logger log = LoggerFactory.getLogger(ResultsManager.class);

	@PetiteInject
	protected ContextInjectorComponent contextInjectorComponent;
	@PetiteInject
	protected MadvocConfig madvocConfig;

	public ResultsManager() {
		this.stringResults = new HashMap<>();
		this.allResults = new HashMap<>();
		this.typeResults = new HashMap<>();
	}

	// ---------------------------------------------------------------- container

	protected final Map stringResults;
	protected final Map typeResults;
	protected final Map, ActionResult> allResults;

	/**
	 * Returns all action results.
	 */
	public Set getAllActionResults() {
		Set set = new HashSet<>(allResults.size());
		set.addAll(allResults.values());
		return set;
	}

	/**
	 * Registers an action result handler and returns created {@link jodd.madvoc.result.ActionResult} if
	 * result with same type doesn't exist. Otherwise, returns existing result and created one will be ignored.
	 */
	public ActionResult register(Class resultClass) {
		return register(createResult(resultClass));
	}

	/**
	 * Registers new action result instance. If action result of the same class is already
	 * registered, registration will be skipped. If result for the same result type or
	 * same target class exist, it will be replaced! However, default Jodd results will
	 * never replace other results. After the registration, results are initialized.
	 */
	protected ActionResult register(ActionResult result) {
		Class actionResultClass = result.getClass();

		// check existing

		ActionResult existingResult = allResults.get(actionResultClass);

		if (existingResult != null) {
			if (log.isDebugEnabled()) {
				log.debug("ActionResult already registered: " + actionResultClass);
			}
			return existingResult;
		}

		// + string hook

		String resultName = result.getResultName();

		if (resultName != null) {
			existingResult = stringResults.get(resultName);

			if (existingResult != null) {
				// the same result name exist
				if (!resultMayReplaceExistingOne(actionResultClass)) {
					if (log.isDebugEnabled()) {
						log.debug("ActionResult already registered: " + actionResultClass);
					}
					return existingResult;
				}

				// allow only one action result per result type
				allResults.remove(existingResult.getClass());
			}

			if (log.isInfoEnabled()) {
				log.debug("ActionResult registered: " + resultName + " -> " + actionResultClass);
			}

			stringResults.put(resultName, result);
		}

		// + type result

		Class resultValueType = result.getResultValueType();

		if (resultValueType != null && resultValueType != String.class) {
			existingResult = typeResults.get(resultValueType);

			if (existingResult != null) {
				if (!resultMayReplaceExistingOne(actionResultClass)) {
					if (log.isDebugEnabled()) {
						log.debug("ActionResult already registered: " + actionResultClass);
					}
					return existingResult;
				}

				// allow only one action result per result type
				allResults.remove(existingResult.getClass());
			}

			if (log.isInfoEnabled()) {
				log.debug("ActionResult registered: " + resultValueType + " -> " + actionResultClass);
			}

			typeResults.put(resultValueType, result);
		}

		// + all results

		if (log.isInfoEnabled()) {
			log.debug("ActionResult registered: " + actionResultClass);
		}

		allResults.put(actionResultClass, result);

		// + init

		initializeResult(result);

		return result;
	}

	/**
	 * Returns true if action result can replace existing one.
	 * This rule makes sure that Jodd's default results never replace custom
	 * results. This rule is important since result are found on classpath
	 * and can be registered without any order.
	 */
	protected boolean resultMayReplaceExistingOne(Class actionResultClass) {
		String packageName = actionResultClass.getPackage().getName();
		return !packageName.startsWith("jodd.");
	}

	// ---------------------------------------------------------------- lookup

	/**
	 * Lookups for action result and {@link #register(Class) registers} it if missing.
	 */
	private ActionResult lookupAndRegisterIfMissing(Class actionResultClass) {
		ActionResult actionResult = allResults.get(actionResultClass);

		if (actionResult == null) {
			actionResult = register(actionResultClass);
		}

		return actionResult;
	}

	/**
	 * Lookups for {@link jodd.madvoc.result.ActionResult action result handler}
	 * based on current {@link jodd.madvoc.ActionRequest action request} and action method
	 * result object. Lookup performs the following in given order:
	 * 
    *
  • if result object is null, check if {@link jodd.madvoc.result.Result} is used
  • *
  • check result definition in @Action annotation
  • *
  • if result is not a String, check if it is annotated with {@link jodd.madvoc.meta.RenderWith} annotation
  • *
  • if result is not a String, find ActionResult for matching result object type
  • *
  • if action result still not found, call toString on result object and parse it
  • *
*/ public ActionResult lookup(ActionRequest actionRequest, Object resultObject) { ActionResult actionResult = null; // + special class: result if (resultObject == null) { Result result = actionRequest.getResult(); if (result != null) { // read Result, if used; if not, values will be null Class actionResultClass = result.getActionResult(); resultObject = result.getResultValue(); if (resultObject == null) { resultObject = result.value(); } if (actionResultClass != null) { actionResult = lookupAndRegisterIfMissing(actionResultClass); } } } if (actionResult == null) { // + still not found, read @Action value ActionConfig actionConfig = actionRequest.getActionConfig(); Class actionResultClass = actionConfig.getActionResult(); if (actionResultClass != null) { actionResult = lookupAndRegisterIfMissing(actionResultClass); } } if (actionResult == null && resultObject != null) { Class resultType = resultObject.getClass(); if (resultType != String.class) { // + still not found, read @RenderWith value if exist RenderWith renderWith = resultObject.getClass().getAnnotation(RenderWith.class); if (renderWith != null) { actionResult = lookupAndRegisterIfMissing(renderWith.value()); } if (actionResult == null) { // + still not found, lookup for type actionResult = typeResults.get(resultObject.getClass()); } } } if (actionResult == null) { // + still not found, toString() ActionResult defaultActionResult = lookupAndRegisterIfMissing(madvocConfig.getDefaultActionResult()); if (stringResults.isEmpty()) { // no string results registered, carry on with the defaults. actionResult = defaultActionResult; } else { String resultValue = resultObject != null ? resultObject.toString() : null; String resultName = null; // first check result value if (resultValue != null) { int columnIndex = resultValue.indexOf(':'); if (columnIndex != -1) { resultName = resultValue.substring(0, columnIndex); resultValue = resultValue.substring(columnIndex + 1); } } if (resultName != null) { actionResult = stringResults.get(resultName); } else { actionResult = defaultActionResult; } if (actionResult.getResultName() != null) { // convert remaining of the string to result object // only when action result is string result try { Class targetClass = actionResult.getResultValueType(); if (targetClass == null || targetClass == String.class) { resultObject = resultValue; } else { resultObject = TypeConverterManager.convertType(resultValue, targetClass); } } catch (Exception ex) { resultObject = resultValue; } } } } // set action result object into action request! actionRequest.setActionResult(resultObject); return actionResult; } // ---------------------------------------------------------------- init /** * Initializes action result. */ protected void initializeResult(ActionResult result) { contextInjectorComponent.injectContext(new Target(result)); result.init(); } // ---------------------------------------------------------------- create /** * Creates new {@link jodd.madvoc.result.ActionResult}. */ protected ActionResult createResult(Class actionResultClass) { try { return actionResultClass.newInstance(); } catch (Exception ex) { throw new MadvocException("Invalid Madvoc result: " + actionResultClass, ex); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy