/* * Sakuli - Testing and Monitoring-Tool for Websites and common UIs. * * Copyright 2013 - 2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sakuli.aop; import net.sf.sahi.report.Report; import net.sf.sahi.report.ResultType; import net.sf.sahi.rhino.RhinoScriptRunner; import org.apache.commons.lang.ArrayUtils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.sakuli.actions.logging.LogToResult; import org.sakuli.datamodel.actions.LogResult; import org.sakuli.loader.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import static org.apache.commons.lang.StringUtils.isNotEmpty; import static org.apache.commons.lang.StringUtils.removeEnd; import static org.apache.commons.lang3.StringUtils.removeStart; /** * Aspect for the External Sahi Library {@link net.sf.sahi} * * @author tschneck Date: 17.10.13 */ @Aspect @Component public class RhinoAspect extends BaseSakuliAspect { public static final String ALREADY_PROCESSED = "{{SAKULI_EX}}"; protected final static Logger logger = LoggerFactory.getLogger(RhinoAspect.class); /** * Aspect to fetch the {@link RhinoScriptRunner} at the start of a test case script. The {@link RhinoScriptRunner} * will then saved in the {@link BaseActionLoaderImpl} for forther usage. * * @param joinPoint injected joinPoint of the execution */ @After("execution(* net.sf.sahi.rhino.RhinoScriptRunner.setReporter*(*))") public void getRhinoScriptRunner(JoinPoint joinPoint) { BaseActionLoader environmentLoader = BeanLoader.loadBaseActionLoader(); if (joinPoint.getTarget() instanceof RhinoScriptRunner) { logger.info("Add RhinoScriptRunner to the JavaBackEnd"); environmentLoader.setRhinoScriptRunner((RhinoScriptRunner) joinPoint.getTarget()); } else { logger.warn(joinPoint.getTarget().getClass().getName() + " could not added to the JavaBackEnd!"); } } /** * Pointcut for the {@link org.sakuli.actions.TestCaseAction} class to do an {@link * #addActionLog(org.aspectj.lang.JoinPoint, org.sakuli.actions.logging.LogToResult)} */ @Before("execution(* org.sakuli.actions.TestCaseAction.*(..)) &&" + "@annotation(logToResult)") public void doTestCaseActionLog(JoinPoint joinPoint, LogToResult logToResult) { addActionLog(joinPoint, logToResult); } /** * Pointcut for the {@link org.sakuli.actions.environment} classes to do an {@link * #addActionLog(org.aspectj.lang.JoinPoint, org.sakuli.actions.logging.LogToResult)} */ @Before("execution(* org.sakuli.actions.screenbased.*.*(..)) &&" + "@annotation(logToResult)") public void doScreenBasedActionLog(JoinPoint joinPoint, LogToResult logToResult) { addActionLog(joinPoint, logToResult); } /** * Pointcut for the {@link org.sakuli.actions.environment} classes to do an {@link * #addActionLog(org.aspectj.lang.JoinPoint, org.sakuli.actions.logging.LogToResult)} */ @Before("execution(* org.sakuli.actions.environment.*.*(..)) &&" + "@annotation(logToResult)") public void doEnvironmentLog(JoinPoint joinPoint, LogToResult logToResult) { addActionLog(joinPoint, logToResult); } /** * Pointcut for the {@link org.sakuli.actions.logging} classes to do an {@link #addActionLog(org.aspectj.lang.JoinPoint, * org.sakuli.actions.logging.LogToResult)} */ @Before("execution(* org.sakuli.actions.logging.*.*(..)) &&" + "@annotation(logToResult)") public void doLoggingLog(JoinPoint joinPoint, LogToResult logToResult) { addActionLog(joinPoint, logToResult); } /** * Method to do all Logs for the action classes annotated with {@link org.sakuli.actions.logging.LogToResult}. A log * entry will created at the sakuli log files and at the sahi HTML {@link net.sf.sahi.report.Report}. * * @param joinPoint {@link JoinPoint} object of the calling aspect * @param logToResult {@link LogToResult} Annotation */ protected void addActionLog(JoinPoint joinPoint, LogToResult logToResult) { Logger logger = getLogger(joinPoint); if (logToResult != null) { StringBuilder message = createLoggingString(joinPoint, logToResult); //log the action to log file and print switch (logToResult.level()) { case ERROR: logger.error(message.toString()); break; case INFO: logger.info(message.toString()); break; case DEBUG: logger.debug(message.toString()); break; case WARNING: logger.warn(message.toString()); message.insert(0, "WARNING: "); break; } if (logToResult.level().getResultType() != null) { Report sahiReport = BeanLoader.loadBaseActionLoader().getSahiReport(); if (sahiReport != null) { sahiReport.addResult( message.toString(), logToResult.level().getResultType(), joinPoint.getSignature().getDeclaringTypeName(), ""); } } } } /** * @return based on the different arguments of the {@link LogToResult} annotation an different output {@link String} */ protected StringBuilder createLoggingString(JoinPoint joinPoint, LogToResult logToResult) { if (logToResult.logArgsOnly()) { return new StringBuilder(removeEnd(removeStart(printArgs(joinPoint, logToResult.logArgs()), "["), "]")); } StringBuilder message = new StringBuilder(); //log class instance? if (logToResult.logClassInstance() && joinPoint.getTarget() != null) { message.append("\"").append(joinPoint.getTarget().toString()).append("\" "); } message.append(getClassAndMethodAsString(joinPoint)); //add message if needed if (isNotEmpty(logToResult.message())) { message.append(" - ").append(logToResult.message()); } //add args if needed if (ArrayUtils.isNotEmpty(joinPoint.getArgs())) { message.append(" with arg(s) ").append(printArgs(joinPoint, logToResult.logArgs())); } return message; } /** * Aspect to fetch all Logs from the Sahi-Proxy by the method {@link net.sf.sahi.ant.Report} and do an trusty * exception handling on top of that. * * @param joinPoint injected joinPoint of the execution */ @Before("execution(* net.sf.sahi.report.Report.addResult(..))") public void doHandleRhinoException(JoinPoint joinPoint) { // Read out all args Object[] args = joinPoint.getArgs(); ResultType resultType; if (args[1] instanceof ResultType) { resultType = (ResultType) args[1]; } else { resultType = ResultType.getType((String) args[1]); } LogResult logResult = new LogResult( (String) args[0], resultType, (String) args[2], (String) args[3] ); if (logResult.getFailureMsg() == null || !logResult.getFailureMsg().contains(ALREADY_PROCESSED)) { //log and handle exception from sahi actions if (ResultType.ERROR.equals(resultType) || ResultType.FAILURE.equals(resultType)) { BaseActionLoader environmentLoader = BeanLoader.loadBaseActionLoader(); environmentLoader.getExceptionHandler().handleException(logResult); } /** * all Actions in Package {@link org.sakuli.actions} should be already logged by * {@link #doAddActionLog(org.aspectj.lang.JoinPoint, org.sakuli.actions.logging.LogToResult)}. */ else if (logResult.getDebugInfo() == null || !logResult.getDebugInfo().startsWith("org.sakuli.actions.")) { logger.info(logResult.getMessage()); } } } }