/*
* Copyright (c) 2010-2014 Evolveum
*
* 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 com.evolveum.midpoint.testing.model.client.sample;
import com.evolveum.midpoint.model.client.ModelClientUtil;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ExecuteScriptsOptionsType;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.OutputFormatType;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.SingleScriptOutputType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultStatusType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.ExecuteScriptsResponseType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.ExecuteScriptsType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.ModelPortType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.ModelService;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.io.IOUtils;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.wss4j.dom.WSConstants;
import org.apache.wss4j.dom.handler.WSHandlerConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* @author mederly
*
*/
public class RunScript {
// Configuration
public static final String ADM_USERNAME = "administrator";
public static final String ADM_PASSWORD = "5ecr3t";
private static final String DEFAULT_ENDPOINT_URL = "http://localhost:8080/midpoint/model/model-3";
private static final String PROPERTY_PREFIX = "[[!!";
private static final String PROPERTY_SUFFIX = "!!]]";
private static final String OPT_HELP = "h";
public static final String OPT_SCRIPT = "s";
public static final String OPT_URL = "url";
public static final String OPT_USER = "u";
public static final String OPT_PASSWORD = "p";
public static final String OPT_FILE_FOR_DATA = "fd";
public static final String OPT_FILE_FOR_CONSOLE = "fc";
public static final String OPT_FILE_FOR_RESULT = "fr";
public static final String OPT_HIDE_DATA = "hd";
public static final String OPT_HIDE_SCRIPT = "hs";
public static final String OPT_HIDE_CONSOLE = "hc";
public static final String OPT_HIDE_RESULT = "hr";
public static final String OPT_SHOW_RESULT = "sr";
/**
* @param args
*/
public static void main(String[] args) {
try {
Options options = new Options();
options.addOption(OPT_HELP, "help", false, "Print this help information");
options.addOption(OPT_SCRIPT, "script", true, "Script file (XML for the moment)");
options.addOption(OPT_URL, true, "Endpoint URL (default: " + DEFAULT_ENDPOINT_URL + ")");
options.addOption(OPT_USER, "user", true, "User name (default: " + ADM_USERNAME + ")");
options.addOption(OPT_PASSWORD, "password", true, "Password");
options.addOption(OPT_FILE_FOR_DATA, "file-for-data", true, "Name of the file to write resulting XML data into");
options.addOption(OPT_FILE_FOR_CONSOLE, "file-for-console", true, "Name of the file to write resulting console output into");
options.addOption(OPT_FILE_FOR_RESULT, "file-for-result", true, "Name of the file to write operation result into");
options.addOption(OPT_HIDE_DATA, "hide-data", false, "Don't display data output");
options.addOption(OPT_HIDE_SCRIPT, "hide-script", false, "Don't display input script");
options.addOption(OPT_HIDE_CONSOLE, "hide-console", false, "Don't display console output");
options.addOption(OPT_HIDE_RESULT, "hide-result", false, "Don't display detailed operation result (default: showing if not SUCCESS)");
options.addOption(OPT_SHOW_RESULT, "show-result", false, "Always show detailed operation result (default: showing if not SUCCESS)");
options.addOption(
OptionBuilder.withArgName("property=value")
.hasArgs(2)
.withValueSeparator()
.withDescription("use value for given property")
.create("D"));
CommandLineParser parser = new GnuParser();
CommandLine cmdline = parser.parse(options, args);
if (!cmdline.hasOption(OPT_SCRIPT) || cmdline.hasOption("h")) {
HelpFormatter helpFormatter = new HelpFormatter();
helpFormatter.printHelp("runscript", options);
System.exit(0);
}
ExecuteScriptsType request = new ExecuteScriptsType();
String script = readXmlFile(cmdline.getOptionValue(OPT_SCRIPT));
script = replaceParameters(script, cmdline.getOptionProperties("D"));
request.setMslScripts(script); // todo fix this hack
ExecuteScriptsOptionsType optionsType = new ExecuteScriptsOptionsType();
optionsType.setOutputFormat(OutputFormatType.MSL); // todo fix this hack
request.setOptions(optionsType);
if (!cmdline.hasOption(OPT_HIDE_SCRIPT)) {
System.out.println("\nScript to execute:\n" + script);
}
System.out.println("=================================================================");
ModelPortType modelPort = createModelPort(cmdline);
ExecuteScriptsResponseType response = modelPort.executeScripts(request);
System.out.println("=================================================================");
for (SingleScriptOutputType output : response.getOutputs().getOutput()) {
if (!cmdline.hasOption(OPT_HIDE_DATA)) {
System.out.println("Data:\n" + output.getMslData());
System.out.println("-----------------------------------------------------------------");
}
if (cmdline.hasOption(OPT_FILE_FOR_DATA)) {
IOUtils.write(output.getMslData(), new FileOutputStream(cmdline.getOptionValue(OPT_FILE_FOR_DATA)), "UTF-8");
}
if (!cmdline.hasOption(OPT_HIDE_CONSOLE)) {
System.out.println("Console output:\n" + output.getTextOutput());
}
if (cmdline.hasOption(OPT_HIDE_CONSOLE)) {
IOUtils.write(output.getMslData(), new FileWriter(cmdline.getOptionValue(OPT_FILE_FOR_CONSOLE)));
}
}
System.out.println("=================================================================");
System.out.println("Operation result: " + getResultStatus(response.getResult()));
if (!cmdline.hasOption(OPT_HIDE_RESULT) && (cmdline.hasOption(OPT_SHOW_RESULT) || response.getResult() == null || response.getResult().getStatus() != OperationResultStatusType.SUCCESS)) {
System.out.println("\n\n" + marshalResult(response.getResult()));
}
if (cmdline.hasOption(OPT_FILE_FOR_RESULT)) {
IOUtils.write(marshalResult(response.getResult()), new FileWriter(cmdline.getOptionValue(OPT_FILE_FOR_RESULT)));
}
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
private static String getResultStatus(OperationResultType result) {
if (result == null) {
return "(null)";
} else {
return result.getStatus() + (result.getMessage() != null ? (": " + result.getMessage()) : "");
}
}
private static String marshalResult(OperationResultType result) throws JAXBException, FileNotFoundException {
if (result == null) {
return "";
} else {
return marshalObject(new JAXBElement<>(new QName("result"), OperationResultType.class, result));
}
}
private static String replaceParameters(String script, Properties properties) {
for (Map.Entry entry : properties.entrySet()) {
String key = PROPERTY_PREFIX + entry.getKey() + PROPERTY_SUFFIX;
if (!script.contains(key)) {
throw new IllegalStateException("Property " + key + " is not present in the script");
}
script = script.replace(key, (String) entry.getValue());
}
int i = script.indexOf(PROPERTY_PREFIX);
if (i != -1) {
int j = script.indexOf(PROPERTY_SUFFIX, i);
if (j == -1) {
j = script.length();
}
throw new IllegalStateException("Unresolved property " + script.substring(i, j+PROPERTY_SUFFIX.length()));
}
return script;
}
// brutally hacked - reads XML file in correct encoding
private static String readXmlFile(String filename) throws IOException {
String encoding = determineEncoding(filename);
FileInputStream fis = new FileInputStream(filename);
String data = IOUtils.toString(fis, encoding);
fis.close();
return data;
}
private static String determineEncoding(String filename) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(filename));
StringBuilder sb = new StringBuilder();
for (;;) {
int c = br.read();
if (c == -1) {
throw new IllegalStateException("No XML declaration found in file " + filename);
}
sb.append((char) c);
if (c == '>') {
break;
}
}
br.close();
String xmldecl = sb.toString();
if (!xmldecl.startsWith("<?xml")) {
throw new IllegalStateException("No XML declaration found in file " + filename);
}
int encodingPos = xmldecl.indexOf("encoding");
if (encodingPos == -1) {
return System.getProperty("file.encoding");
}
int from1 = xmldecl.indexOf("\'", encodingPos);
int from2 = xmldecl.indexOf("\"", encodingPos);
if (from1 == -1 && from2 == -1) {
throw new IllegalStateException("Incorrect encoding information in XML declaration: " + xmldecl);
}
int from, to;
if (from1 != -1 && from1 < from2) {
from = from1;
to = xmldecl.indexOf("\'", from1+1);
} else {
from = from2;
to = xmldecl.indexOf("\"", from2+1);
}
if (to == -1) {
throw new IllegalStateException("Incorrect encoding information in XML declaration: " + xmldecl);
}
return xmldecl.substring(from+1, to);
}
private static <T> T unmarshalFile(File file) throws JAXBException, FileNotFoundException {
JAXBContext jc = getJaxbContext();
Unmarshaller unmarshaller = jc.createUnmarshaller();
InputStream is = null;
JAXBElement<T> element = null;
try {
is = new FileInputStream(file);
element = (JAXBElement<T>) unmarshaller.unmarshal(is);
} finally {
if (is != null) {
IOUtils.closeQuietly(is);
}
}
if (element == null) {
return null;
}
return element.getValue();
}
private static JAXBContext jaxbContext = null;
private static JAXBContext getJaxbContext() throws JAXBException {
if (jaxbContext == null) {
jaxbContext = ModelClientUtil.instantiateJaxbContext();
}
return jaxbContext;
}
private static String marshalObject(Object object) throws JAXBException, FileNotFoundException {
JAXBContext jc = getJaxbContext();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter sw = new StringWriter();
marshaller.marshal(object, sw);
return sw.toString();
}
private static <T> T unmarshallResouce(String path) throws JAXBException, FileNotFoundException {
JAXBContext jc = getJaxbContext();
Unmarshaller unmarshaller = jc.createUnmarshaller();
InputStream is = null;
JAXBElement<T> element = null;
try {
is = RunScript.class.getClassLoader().getResourceAsStream(path);
if (is == null) {
throw new FileNotFoundException("System resource "+path+" was not found");
}
element = (JAXBElement<T>) unmarshaller.unmarshal(is);
} finally {
if (is != null) {
IOUtils.closeQuietly(is);
}
}
if (element == null) {
return null;
}
return element.getValue();
}
public static ModelPortType createModelPort(CommandLine cmdLine) {
String endpointUrl = cmdLine.getOptionValue(OPT_URL, DEFAULT_ENDPOINT_URL);
String user = cmdLine.getOptionValue(OPT_USER, ADM_USERNAME);
ClientPasswordHandler.setPassword(cmdLine.getOptionValue(OPT_PASSWORD, ADM_PASSWORD));
System.out.println("Endpoint URL: " + endpointUrl);
ModelService modelService = new ModelService();
ModelPortType modelPort = modelService.getModelPort();
BindingProvider bp = (BindingProvider)modelPort;
Map<String, Object> requestContext = bp.getRequestContext();
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointUrl);
org.apache.cxf.endpoint.Client client = ClientProxy.getClient(modelPort);
org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();
Map<String,Object> outProps = new HashMap<>();
outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
outProps.put(WSHandlerConstants.USER, user);
outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST);
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordHandler.class.getName());
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
cxfEndpoint.getOutInterceptors().add(wssOut);
return modelPort;
}
}