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

io.openliberty.arquillian.managed.exceptions.SupportFeatureTextExceptionLocator Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2018, 2022 IBM Corporation, Red Hat Middleware LLC, and individual contributors
 * identified by the Git commit log. 
 *
 * 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 io.openliberty.arquillian.managed.exceptions;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

import io.openliberty.arquillian.managed.exceptions.NestedExceptionBuilder.ExMsg;

/**
 * Tries to receive information about an exception from the server in text form
 * 

* This relies on the liberty-support-jakarta-feature being installed and running *

* The text format expected from the server includes information about the * exception and its cause chain. *

* For each exception in the cause chain, the following information is returned: *

    *
  • the class name
  • *
  • the names of all superclasses (if any)
  • *
  • the exception message
  • *
*

* Example: * *

 * 
 * exClass com.example.Exception
 * exSuperclass com.example.SuperclassOfException
 * exSuperclass com.example.SuperclassOfSuperclassOfException
 * This is the exception message
 * which can have multiple lines
 * exClass com.example.CauseOfException
 * Exception cause message
 * ...
 * 
 * 
*

* This strategy for retrieving exceptions does not retain as much information * as retrieving a serialized object (in particular the stack trace is lost) but * it's much more robust against missing classes on the client. If one class in * the cause chain can't be loaded, other classes in the chain can still be * loaded. In addition, if a class in can't be loaded, we also attempt to load * classes in its type hierarchy instead. This should catch most cases where a * test requires that a spec exception is thrown but liberty throws an exception * which subclasses it. The subclass may not be available to the client but the * spec exception must be (since it was referenced from the test). * */ public class SupportFeatureTextExceptionLocator implements DeploymentExceptionLocator { private final static Logger log = Logger.getLogger(SupportFeatureTextExceptionLocator.class.getName()); private final MBeanServerConnection mbsc; private final ObjectName on; private static final Pattern CLASS_PATTERN = Pattern.compile("exClass (.*)"); private static final Pattern SUPERCLASS_PATTERN = Pattern.compile("exSuperclass (.*)"); public SupportFeatureTextExceptionLocator(MBeanServerConnection mbsc) { this.mbsc = mbsc; StringBuilder sb = new StringBuilder("LibertyArquillian:"); sb.append("type=").append("DeploymentExceptionMBean"); try { on = new ObjectName(sb.toString()); } catch (MalformedObjectNameException e) { // Shouldn't happen as most of the URI parts are hard coded throw new IllegalArgumentException("Invalid ObjectName: " + sb.toString() + " " + e, e); } } @Override public Throwable getException(String appName, String logLine, long deploymentTime) { try { Object[] response = (Object[]) mbsc.invoke(on, "getDeploymentException", new String[] { appName, "text" }, new String[] { String.class.getName(), String.class.getName() }); int status = ((Integer) response[0]).intValue(); if (status == 400) { log.warning("After " + appName + " failed to start, the server did not report an exception for that app"); } else if (status != 200) { log.info("Unable to receive text format exception from server, is usr:arquillian-support-jakarta-2.1 installed?"); } else { log.finer("Reading exception returned from server"); try (BufferedReader reader = new BufferedReader(new StringReader((String) response[1]))) { return readResponse(reader); } } } catch (IOException ex) { log.warning("IO Exception trying to get text exception: " + ex); } catch (Exception ex) { log.warning("Unexpected exception thrown while trying to get text exception: " + ex); } return null; } private Throwable readResponse(BufferedReader reader) throws IOException { String line; ResponseReader responseReader = new ResponseReader(); while ((line = reader.readLine()) != null) { Matcher classMatcher = CLASS_PATTERN.matcher(line); if (classMatcher.matches()) { responseReader.readClass(classMatcher.group(1)); continue; } Matcher superclassMatcher = SUPERCLASS_PATTERN.matcher(line); if (superclassMatcher.matches()) { responseReader.readSuperclass(superclassMatcher.group(1)); continue; } responseReader.readMessage(line); } responseReader.finishMsg(); List msgs = responseReader.finish(); return NestedExceptionBuilder.buildNestedException(msgs); } private static class ResponseReader { List msgs = new ArrayList<>(); ExMsg currentMsg = null; StringBuilder messageBuilder = null; private void readClass(String className) { log.finer("Read class " + className); finishMsg(); currentMsg.exName = className; } private void readSuperclass(String className) { log.finer("Read superclass" + className); currentMsg.superclasses.add(className); } private void readMessage(String message) { log.finer("Read message " + message); if (messageBuilder == null) { messageBuilder = new StringBuilder(); } else { messageBuilder.append("\n"); } messageBuilder.append(message); } private void finishMsg() { if (currentMsg != null) { msgs.add(currentMsg); if (messageBuilder != null) { currentMsg.logMsg = messageBuilder.toString(); } } currentMsg = new ExMsg(); messageBuilder = null; } private List finish() { return msgs; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy