/**
* Mule Development Kit
* Copyright 2010-2011 (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
*
* 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.mule.devkit.generation.adapter;
import oauth.signpost.OAuthConsumer;
import oauth.signpost.OAuthProvider;
import oauth.signpost.basic.DefaultOAuthConsumer;
import oauth.signpost.basic.DefaultOAuthProvider;
import oauth.signpost.exception.OAuthCommunicationException;
import oauth.signpost.exception.OAuthExpectationFailedException;
import oauth.signpost.exception.OAuthMessageSignerException;
import oauth.signpost.exception.OAuthNotAuthorizedException;
import oauth.signpost.signature.AuthorizationHeaderSigningStrategy;
import oauth.signpost.signature.HmacSha1MessageSigner;
import oauth.signpost.signature.PlainTextMessageSigner;
import oauth.signpost.signature.QueryStringSigningStrategy;
import org.mule.api.annotations.oauth.OAuth;
import org.mule.api.annotations.oauth.OAuthConsumerKey;
import org.mule.api.annotations.oauth.OAuthConsumerSecret;
import org.mule.api.annotations.oauth.OAuthMessageSigner;
import org.mule.api.annotations.oauth.OAuthScope;
import org.mule.api.annotations.oauth.OAuthSigningStrategy;
import org.mule.api.oauth.OAuth1Adapter;
import org.mule.api.oauth.UnableToAcquireAccessTokenException;
import org.mule.api.oauth.UnableToAcquireRequestTokenException;
import org.mule.devkit.generation.AbstractOAuthAdapterGenerator;
import org.mule.devkit.generation.DevKitTypeElement;
import org.mule.devkit.generation.GenerationException;
import org.mule.devkit.model.code.Block;
import org.mule.devkit.model.code.CatchBlock;
import org.mule.devkit.model.code.Conditional;
import org.mule.devkit.model.code.DefinedClass;
import org.mule.devkit.model.code.ExpressionFactory;
import org.mule.devkit.model.code.FieldVariable;
import org.mule.devkit.model.code.Invocation;
import org.mule.devkit.model.code.Method;
import org.mule.devkit.model.code.Modifier;
import org.mule.devkit.model.code.Op;
import org.mule.devkit.model.code.TryStatement;
import org.mule.devkit.model.code.Variable;
import org.mule.devkit.model.code.builders.FieldBuilder;
import javax.lang.model.element.TypeElement;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class OAuth1AdapterGenerator extends AbstractOAuthAdapterGenerator {
private static final String REQUEST_TOKEN_FIELD_NAME = "requestToken";
private static final String REQUEST_TOKEN_SECRET_FIELD_NAME = "requestTokenSecret";
private static final String CONSUMER_FIELD_NAME = "consumer";
@Override
protected boolean shouldGenerate(DevKitTypeElement typeElement) {
return typeElement.hasAnnotation(OAuth.class);
}
@Override
protected void doGenerate(DevKitTypeElement typeElement) throws GenerationException {
DefinedClass oauthAdapter = getOAuthAdapterClass(typeElement, "OAuth1Adapter", OAuth1Adapter.class);
OAuth oauth = typeElement.getAnnotation(OAuth.class);
authorizationCodePatternConstant(oauthAdapter, oauth.verifierRegex());
muleContextField(oauthAdapter);
// logger field
FieldVariable logger = generateLoggerField(oauthAdapter);
FieldVariable requestToken = requestTokenField(oauthAdapter);
FieldVariable requestTokenSecret = requestTokenSecretField(oauthAdapter);
FieldVariable oauthVerifier = authorizationCodeField(oauthAdapter);
FieldVariable saveAccessTokenCallback = saveAccessTokenCallbackField(oauthAdapter);
FieldVariable restoreAccessTokenCallback = restoreAccessTokenCallbackField(oauthAdapter);
FieldVariable redirectUrl = redirectUrlField(oauthAdapter);
FieldVariable oauthAccessToken = accessTokenField(oauthAdapter);
FieldVariable oauthAccessTokenSecret = oauthAccessTokenSecretField(oauthAdapter);
consumerField(oauthAdapter);
oauthCallbackField(oauthAdapter);
DefinedClass messageProcessor = generateMessageProcessorInnerClass(oauthAdapter);
Method createConsumer = generateCreateConsumerMethod(oauthAdapter, oauth, typeElement);
generateStartMethod(oauthAdapter);
generateStopMethod(oauthAdapter);
generateInitialiseMethod(oauthAdapter, messageProcessor, createConsumer, oauth);
generateGetAuthorizationUrlMethod(oauthAdapter, requestToken, requestTokenSecret, redirectUrl, typeElement, oauth, logger);
generateRestoreAccessTokenMethod(oauthAdapter, restoreAccessTokenCallback, logger);
generateFetchAccessTokenMethod(oauthAdapter, requestToken, requestTokenSecret, saveAccessTokenCallback, oauthVerifier, typeElement, oauth, logger);
generateHasBeenAuthorizedMethod(oauthAdapter, oauthAccessToken);
generateOverrides(typeElement, oauthAdapter, oauthAccessToken, oauthAccessTokenSecret);
}
private FieldVariable requestTokenField(DefinedClass oauthAdapter) {
return new FieldBuilder(oauthAdapter).type(String.class).name(REQUEST_TOKEN_FIELD_NAME).build();
}
private FieldVariable requestTokenSecretField(DefinedClass oauthAdapter) {
return new FieldBuilder(oauthAdapter).type(String.class).name(REQUEST_TOKEN_SECRET_FIELD_NAME).build();
}
private FieldVariable oauthAccessTokenSecretField(DefinedClass oauthAdapter) {
return new FieldBuilder(oauthAdapter).type(String.class).name(OAUTH_ACCESS_TOKEN_SECRET_FIELD_NAME).getterAndSetter().build();
}
private FieldVariable consumerField(DefinedClass oauthAdapter) {
return new FieldBuilder(oauthAdapter).type(OAuthConsumer.class).name(CONSUMER_FIELD_NAME).build();
}
private Method generateCreateConsumerMethod(DefinedClass oauthAdapter, OAuth oauth, TypeElement typeElement) {
Method createConsumer = oauthAdapter.method(Modifier.PRIVATE, context.getCodeModel().VOID, "createConsumer");
Invocation getConsumerKey = ExpressionFactory.invoke(getterMethodForFieldAnnotatedWith(typeElement, OAuthConsumerKey.class));
Invocation getConsumerSecret = ExpressionFactory.invoke(getterMethodForFieldAnnotatedWith(typeElement, OAuthConsumerSecret.class));
FieldVariable consumer = oauthAdapter.fields().get(CONSUMER_FIELD_NAME);
createConsumer.body().assign(consumer, ExpressionFactory._new(ref(DefaultOAuthConsumer.class)).arg(getConsumerKey).arg(getConsumerSecret));
if (oauth.messageSigner().equals(OAuthMessageSigner.HMAC_SHA1)) {
createConsumer.body().invoke(consumer, "setMessageSigner").arg(ExpressionFactory._new(ref(HmacSha1MessageSigner.class)));
} else if (oauth.messageSigner().equals(OAuthMessageSigner.PLAIN_TEXT)) {
createConsumer.body().invoke(consumer, "setMessageSigner").arg(ExpressionFactory._new(ref(PlainTextMessageSigner.class)));
}
if (oauth.signingStrategy().equals(OAuthSigningStrategy.AUTHORIZATION_HEADER)) {
createConsumer.body().invoke(consumer, "setSigningStrategy").arg(ExpressionFactory._new(ref(AuthorizationHeaderSigningStrategy.class)));
} else if (oauth.signingStrategy().equals(OAuthSigningStrategy.QUERY_STRING)) {
createConsumer.body().invoke(consumer, "setSigningStrategy").arg(ExpressionFactory._new(ref(QueryStringSigningStrategy.class)));
}
return createConsumer;
}
private void generateInitialiseMethod(DefinedClass oauthAdapter, DefinedClass messageProcessor, Method createConsumer, OAuth oauth) {
Method initialise = generateInitialiseMethod(oauthAdapter, messageProcessor, oauth.callbackPath());
initialise.body().invoke(createConsumer);
}
private void generateGetAuthorizationUrlMethod(DefinedClass oauthAdapter, FieldVariable requestToken, FieldVariable requestTokenSecret, FieldVariable redirectUrl, DevKitTypeElement typeElement, OAuth oauth, FieldVariable logger) {
Method getAuthorizationUrl = oauthAdapter.method(Modifier.PUBLIC, context.getCodeModel().VOID, GET_AUTHORIZATION_URL_METHOD_NAME);
getAuthorizationUrl._throws(ref(UnableToAcquireRequestTokenException.class));
getAuthorizationUrl.type(ref(String.class));
Variable provider = generateProvider(oauth, getAuthorizationUrl.body(), typeElement);
Variable authorizationUrl = getAuthorizationUrl.body().decl(ref(String.class), "authorizationUrl");
TryStatement tryRetrieveRequestToken = getAuthorizationUrl.body()._try();
FieldVariable consumer = oauthAdapter.fields().get(CONSUMER_FIELD_NAME);
Conditional ifDebugEnabled = tryRetrieveRequestToken.body()._if(logger.invoke("isDebugEnabled"));
Variable messageStringBuilder = ifDebugEnabled._then().decl(ref(StringBuilder.class), "messageStringBuilder", ExpressionFactory._new(ref(StringBuilder.class)));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg("Attempting to acquire a request token "));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("[consumer = ")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(consumer.invoke("getConsumerKey")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("] ")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("[consumerSecret = ")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(consumer.invoke("getConsumerSecret")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("] ")));
ifDebugEnabled._then().add(logger.invoke("debug").arg(messageStringBuilder.invoke("toString")));
tryRetrieveRequestToken.body().assign(authorizationUrl, provider.invoke("retrieveRequestToken").arg(consumer).arg(redirectUrl));
generateReThrow(tryRetrieveRequestToken, OAuthMessageSignerException.class, UnableToAcquireRequestTokenException.class);
generateReThrow(tryRetrieveRequestToken, OAuthNotAuthorizedException.class, UnableToAcquireRequestTokenException.class);
generateReThrow(tryRetrieveRequestToken, OAuthExpectationFailedException.class, UnableToAcquireRequestTokenException.class);
generateReThrow(tryRetrieveRequestToken, OAuthCommunicationException.class, UnableToAcquireRequestTokenException.class);
ifDebugEnabled = tryRetrieveRequestToken.body()._if(logger.invoke("isDebugEnabled"));
messageStringBuilder = ifDebugEnabled._then().decl(ref(StringBuilder.class), "messageStringBuilder", ExpressionFactory._new(ref(StringBuilder.class)));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg("Request token acquired "));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("[requestToken = ")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(consumer.invoke("getToken")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("] ")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("[requestTokenSecret = ")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(consumer.invoke("getTokenSecret")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("] ")));
ifDebugEnabled._then().add(logger.invoke("debug").arg(messageStringBuilder.invoke("toString")));
getAuthorizationUrl.body().assign(requestToken, consumer.invoke("getToken"));
getAuthorizationUrl.body().assign(requestTokenSecret, consumer.invoke("getTokenSecret"));
getAuthorizationUrl.body()._return(authorizationUrl);
}
private void generateRestoreAccessTokenMethod(DefinedClass oauthAdapter, FieldVariable restoreAccessTokenCallbackField, FieldVariable logger)
{
Method restoreAccessTokenMethod = oauthAdapter.method(Modifier.PUBLIC, context.getCodeModel().BOOLEAN, "restoreAccessToken");
Conditional ifRestoreCallbackNotNull = restoreAccessTokenMethod.body()._if(Op.ne(restoreAccessTokenCallbackField, ExpressionFactory._null()));
Conditional ifDebugEnabled = ifRestoreCallbackNotNull._then()._if(logger.invoke("isDebugEnabled"));
Variable messageStringBuilder = ifDebugEnabled._then().decl(ref(StringBuilder.class), "messageStringBuilder", ExpressionFactory._new(ref(StringBuilder.class)));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg("Attempting to restore access token..."));
ifDebugEnabled._then().add(logger.invoke("debug").arg(messageStringBuilder.invoke("toString")));
TryStatement tryToRestore = ifRestoreCallbackNotNull._then()._try();
tryToRestore.body().add(restoreAccessTokenCallbackField.invoke("restoreAccessToken"));
tryToRestore.body().assign(oauthAdapter.fields().get(OAUTH_ACCESS_TOKEN_FIELD_NAME), restoreAccessTokenCallbackField.invoke("getAccessToken"));
tryToRestore.body().assign(oauthAdapter.fields().get(OAUTH_ACCESS_TOKEN_SECRET_FIELD_NAME), restoreAccessTokenCallbackField.invoke("getAccessTokenSecret"));
ifDebugEnabled = tryToRestore.body()._if(logger.invoke("isDebugEnabled"));
messageStringBuilder = ifDebugEnabled._then().decl(ref(StringBuilder.class), "messageStringBuilder", ExpressionFactory._new(ref(StringBuilder.class)));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg("Access token and secret has been restored successfully "));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("[accessToken = ")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(restoreAccessTokenCallbackField.invoke("getAccessToken")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("] ")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("[accessTokenSecret = ")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(restoreAccessTokenCallbackField.invoke("getAccessTokenSecret")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("] ")));
ifDebugEnabled._then().add(logger.invoke("debug").arg(messageStringBuilder.invoke("toString")));
tryToRestore.body()._return(ExpressionFactory.TRUE);
CatchBlock logIfCannotRestore = tryToRestore._catch(ref(Exception.class));
Variable e = logIfCannotRestore.param("e");
logIfCannotRestore.body().add(logger.invoke("error").arg("Cannot restore access token, an unexpected error occurred").arg(e));
ifDebugEnabled._then().add(logger.invoke("debug").arg(messageStringBuilder.invoke("toString")));
restoreAccessTokenMethod.body()._return(ExpressionFactory.FALSE);
}
private void generateFetchAccessTokenMethod(DefinedClass oauthAdapter, FieldVariable requestToken, FieldVariable requestTokenSecret, FieldVariable saveAccessTokenCallback, FieldVariable oauthVerifier, DevKitTypeElement typeElement, OAuth oauth, FieldVariable logger) {
Method fetchAccessToken = oauthAdapter.method(Modifier.PUBLIC, context.getCodeModel().VOID, FETCH_ACCESS_TOKEN_METHOD_NAME);
fetchAccessToken._throws(ref(UnableToAcquireAccessTokenException.class));
fetchAccessToken.body().invoke("restoreAccessToken");
Conditional ifAccessTokenNullOrSecretNull = fetchAccessToken.body()._if(Op.cor(Op.eq(oauthAdapter.fields().get(OAUTH_ACCESS_TOKEN_FIELD_NAME), ExpressionFactory._null()),
Op.eq(oauthAdapter.fields().get(OAUTH_ACCESS_TOKEN_SECRET_FIELD_NAME), ExpressionFactory._null())));
Variable provider = generateProvider(oauth, ifAccessTokenNullOrSecretNull._then(), typeElement);
FieldVariable consumer = oauthAdapter.fields().get(CONSUMER_FIELD_NAME);
ifAccessTokenNullOrSecretNull._then().invoke(consumer, "setTokenWithSecret").arg(requestToken).arg(requestTokenSecret);
TryStatement tryRetrieveAccessToken = ifAccessTokenNullOrSecretNull._then()._try();
Conditional ifDebugEnabled = tryRetrieveAccessToken.body()._if(logger.invoke("isDebugEnabled"));
Variable messageStringBuilder = ifDebugEnabled._then().decl(ref(StringBuilder.class), "messageStringBuilder", ExpressionFactory._new(ref(StringBuilder.class)));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg("Retrieving access token..."));
ifDebugEnabled._then().add(logger.invoke("debug").arg(messageStringBuilder.invoke("toString")));
tryRetrieveAccessToken.body().invoke(provider, "retrieveAccessToken").arg(consumer).arg(oauthVerifier);
generateReThrow(tryRetrieveAccessToken, OAuthMessageSignerException.class, UnableToAcquireAccessTokenException.class);
generateReThrow(tryRetrieveAccessToken, OAuthNotAuthorizedException.class, UnableToAcquireAccessTokenException.class);
generateReThrow(tryRetrieveAccessToken, OAuthExpectationFailedException.class, UnableToAcquireAccessTokenException.class);
generateReThrow(tryRetrieveAccessToken, OAuthCommunicationException.class, UnableToAcquireAccessTokenException.class);
ifAccessTokenNullOrSecretNull._then().assign(oauthAdapter.fields().get(OAUTH_ACCESS_TOKEN_FIELD_NAME), consumer.invoke("getToken"));
ifAccessTokenNullOrSecretNull._then().assign(oauthAdapter.fields().get(OAUTH_ACCESS_TOKEN_SECRET_FIELD_NAME), consumer.invoke("getTokenSecret"));
ifDebugEnabled = ifAccessTokenNullOrSecretNull._then()._if(logger.invoke("isDebugEnabled"));
messageStringBuilder = ifDebugEnabled._then().decl(ref(StringBuilder.class), "messageStringBuilder", ExpressionFactory._new(ref(StringBuilder.class)));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg("Access token retrieved successfully "));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("[accessToken = ")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(oauthAdapter.fields().get(OAUTH_ACCESS_TOKEN_FIELD_NAME)));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("] ")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("[accessTokenSecret = ")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(oauthAdapter.fields().get(OAUTH_ACCESS_TOKEN_SECRET_FIELD_NAME)));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("] ")));
Conditional ifSaveCallbackNotNull = ifAccessTokenNullOrSecretNull._then()._if(Op.ne(saveAccessTokenCallback, ExpressionFactory._null()));
Invocation saveAccessToken = saveAccessTokenCallback.invoke("saveAccessToken").arg(oauthAdapter.fields().get(OAUTH_ACCESS_TOKEN_FIELD_NAME))
.arg(oauthAdapter.fields().get(OAUTH_ACCESS_TOKEN_SECRET_FIELD_NAME));
TryStatement tryToSave = ifSaveCallbackNotNull._then()._try();
ifDebugEnabled = ifSaveCallbackNotNull._then()._if(logger.invoke("isDebugEnabled"));
messageStringBuilder = ifDebugEnabled._then().decl(ref(StringBuilder.class), "messageStringBuilder", ExpressionFactory._new(ref(StringBuilder.class)));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg("Attempting to save access token..."));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("[accessToken = ")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(oauthAdapter.fields().get(OAUTH_ACCESS_TOKEN_FIELD_NAME)));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("] ")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("[accessTokenSecret = ")));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(oauthAdapter.fields().get(OAUTH_ACCESS_TOKEN_SECRET_FIELD_NAME)));
ifDebugEnabled._then().add(messageStringBuilder.invoke("append").arg(ExpressionFactory.lit("] ")));
ifDebugEnabled._then().add(logger.invoke("debug").arg(messageStringBuilder.invoke("toString")));
tryToSave.body().add(saveAccessToken);
CatchBlock logIfCannotSave = tryToSave._catch(ref(Exception.class));
Variable e2 = logIfCannotSave.param("e");
logIfCannotSave.body().add(logger.invoke("error").arg("Cannot save access token, an unexpected error occurred").arg(e2));
}
private Variable generateProvider(OAuth oauth, Block block, DevKitTypeElement typeElement) {
Variable requestTokenUrl = block.decl(ref(String.class), "requestTokenUrl", ExpressionFactory.lit(oauth.requestTokenUrl()));
if (typeElement.hasFieldAnnotatedWith(OAuthScope.class)) {
Variable scope = block.decl(ref(String.class), "scope", ExpressionFactory.invoke(getterMethodForFieldAnnotatedWith(typeElement, OAuthScope.class)));
Block ifScopeNotNull = block._if(Op.ne(scope, ExpressionFactory._null()))._then();
TryStatement tryToEncodeScopeParam = ifScopeNotNull._try();
Variable scopeParam = tryToEncodeScopeParam.body().decl(ref(String.class), "scopeParam", ExpressionFactory.lit("?scope=").invoke("concat").arg(ref(URLEncoder.class).staticInvoke("encode").arg(scope).arg("UTF-8")));
tryToEncodeScopeParam.body().assign(requestTokenUrl, requestTokenUrl.invoke("concat").arg(scopeParam));
generateReThrow(tryToEncodeScopeParam, UnsupportedEncodingException.class, RuntimeException.class);
}
Variable provider = block.decl(ref(OAuthProvider.class), "provider", ExpressionFactory._new(ref(DefaultOAuthProvider.class)).
arg(requestTokenUrl).arg(oauth.accessTokenUrl()).arg(oauth.authorizationUrl()));
block.invoke(provider, "setOAuth10a").arg(ExpressionFactory.TRUE);
return provider;
}
private void generateReThrow(TryStatement tryStatement, Class<? extends Exception> exceptionToCatch, Class<? extends Exception> exceptionToThrow) {
CatchBlock catchBlock = tryStatement._catch(ref(exceptionToCatch));
Variable caughtException = catchBlock.param("e");
catchBlock.body()._throw(ExpressionFactory._new(ref(exceptionToThrow)).arg(caughtException));
}
}