package com.github.approval.reporters; /* * #%L * com.github.nikolavp:approval-core * %% * Copyright (C) 2014 Nikolavp * %% * 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. * #L% */ import com.github.approval.Reporter; import java.io.File; import java.lang.reflect.Method; import java.util.Locale; /** * A reporter that uses a reporter specified in a property value or environment variable. * <p> * The property name is used as is and the environment variable is build by replacing '.' with '_'. So the property * <b>"default.approval.reporter"</b> will be searched as in system properties (-D parameters) and as * <b>"DEFAULT_APPROVAL_REPORTER"</b> in environment variables. * * </p> * <p>This reporter is perfect for * first parameter in {@link Reporters#firstWorking(com.github.approval.Reporter...)}. * </p> * * * @see #getInstance(String) */ public final class SystemPropertyReporter implements Reporter { private Reporter reporter; private SystemPropertyReporter(String classOrFactoryMethod) { try { Class<?> aClass = Class.forName(classOrFactoryMethod); try { Object instance = aClass.getConstructor().newInstance(); if (!(instance instanceof Reporter)) { throw new AssertionError("We got an instance of " + aClass + " but it isn't a reporter!"); } this.reporter = (Reporter) instance; } catch (ReflectiveOperationException e) { throw new AssertionError(aClass + " exists but we couldn't instantiate it!", e); } } catch (ClassNotFoundException e) { int i = classOrFactoryMethod.lastIndexOf('.'); if (i == -1 || i + 1 == classOrFactoryMethod.length()) { throw new AssertionError("Couldn't instantiate class " + classOrFactoryMethod, e); } String possibleClass = classOrFactoryMethod.substring(0, i); String method = classOrFactoryMethod.substring(i + 1); try { Class<?> aClass = Class.forName(possibleClass); try { Method m = aClass.getMethod(method); Object instance = m.invoke(null); if (!(instance instanceof Reporter)) { throw new AssertionError("The instance that was returned from the factory method " + method + " in " + aClass + " is not a reporter"); } this.reporter = (Reporter) instance; } catch (ReflectiveOperationException e1) { throw new AssertionError("Couldn't call static factory method " + method + " in " + aClass, e1); } } catch (ClassNotFoundException e1) { throw new AssertionError("Couldn't find class " + possibleClass, e1); } } } /** * Returns the internal reporter that was constructed from the system property. * * @return the reporter that was constructed */ public Reporter getReporter() { return reporter; } /** * A factory method that returns a reporter which will behave the same as the one specified in propertyName value. * For example the following instance * <pre> * {@code * SystemPropertyReporter.getInstance("e;response.reporter"e;); * } * * </pre> * <p> * will use the reporter that was specified in -Drensponse.reporter on the command line. * The value should be a fully classified class name or a static factory method. Valid values are $packagename.$classname or * $packagename.$classname.$staticmethod * </p> * * @param propertyName the property name from which value we will get the class or the static method * @return the new reporter */ public static Reporter getInstance(String propertyName) { String property = System.getProperty(propertyName); if (property == null) { property = System.getenv(propertyName.replace('.', '_').toUpperCase(Locale.ENGLISH)); } if (property == null) { return Reporters.noop(); } return new SystemPropertyReporter(property); } //visible for testing only static SystemPropertyReporter getInstanceForClassnameOrFactoryMethod(String name) { return new SystemPropertyReporter(name); } @Override public void notTheSame(byte[] oldValue, File fileForVerification, byte[] newValue, File fileForApproval) { reporter.notTheSame(oldValue, fileForVerification, newValue, fileForApproval); } @Override public void approveNew(byte[] value, File fileForApproval, File fileForVerification) { reporter.approveNew(value, fileForApproval, fileForVerification); } @Override public boolean canApprove(File fileForApproval) { return reporter.canApprove(fileForApproval); } }