プログラマ38の日記

主にプログラムメモです。

Excel: VBAでセルの表をtableタグで出力するマクロを作りました

Excelで作成した表をtableタグに変換するVBAマクロを作成しました。

ダウンロードはこちらからになります。

次のように操作します。

①作成した表を選択します。(選択範囲がtableタグになります)
②tableタグ出力ボタンをクリックします。

f:id:crmprogrammer38:20170711093609p:plain

 そうすると、ポップアップされたウインドウにtableタグが出力されます。

f:id:crmprogrammer38:20170711093853p:plain

ポイント
・セルの結合はタグに反映されます。
・セルの背景色や、文字の右寄せ・左寄せはタグに反映されません。

 

 

ツールを作り終わってから思ったのが、同じようなツールは既にあるんじゃないかということでした。
案の定、同じようなツールはたくさんあって無駄なことしたなと思いました。
が、自分が使いたい機能だけに限定されていてこれも悪くないなと思うようにしました。

Java: BeanShellでSalesforceのメタデータ削除ツールを作りました

メタデータを削除したい時があります。

  • 間違えてカスタム項目をたくさん作ってしまった
  • キューを作ると自動で作成されるビューを削除する

こんな時にまとめてメタデータを削除できるツールです。

ツールはbeanshellで作成しています。

 

ダウンロードはこちらからです。

 

通信設定はスクリプトの次の箇所を変更します。

    //1.httpプロキシ情報の入力
    String proxyhost = null;
    Integer proxyport = null;
    String ntlmdomain = null;
    String proxyuser = null;
    String proxypassword = null;


    //2.Salesforceログイン情報の入力
    String sfendpoint = "https://test.salesforce.com/services/Soap/u/40.0";
    String sfusername = "sample@username";
    String sfpassword = "samplepassword";

 

そして、削除したいコンポーネントは、メタデータタイプとともに次のように指定してください。

    //3.削除するメタデータ情報の入力
    //配列に、メタデータタイプと削除するメタデータ物理名を指定します。
    ArrayList fullNames = new ArrayList();

    //以下設定例
    fullNames.add( new String[]{"CustomObject" , "SampleObject__c"} );
    fullNames.add( new String[]{"ListView" , "Opportunity.SampleViewName"} );
    fullNames.add( new String[]{"CustomLabel" , "SampleLabel"} );
    fullNames.add( new String[]{"CustomField" , "Account.SampleField__c"} );

メタデータタイプと、対象コンポーネントを指定すると削除されます。

 

設定ファイルを読み込んで、その設定ファイルに従って処理を組もうとすると、設定ファイルの仕様が発生してしまうと思います。

beanshellであればソースコードをそのまま変更できるので設定ファイルいらずで便利だなと思います。

Java: BeanShellでSalesforceのファイル(添付ファイル、ドキュメント、イベントログ)のエクスポートツールを作りました

SalesforceのバイナリファイルはSOQLで取得することができます。

例えば添付ファイルはAttachmentというオブジェクトから取得できます。


ですが、SOQLでオブジェクトからデータを取得するとbase64エンコードされた文字列となるため、バイナリにデコードしてファイルに出力する処理が必要です。
そこで、ファイルエクスポートツールを作りました。

 

ここからダウンロードしてください。ダウンロードしたzipを解凍すると次のファイルがあります。

f:id:crmprogrammer38:20170630165600p:plain

対象のファイルは添付ファイル(Attachment) 、ドキュメント(Document)、Event Log Files(EventLogFile)の3つを対象としています。
各ファイルは次のようになっています。

バッチファイル スクリプトファイル 説明
batch_Attachment.bat download_Attachment.txt 添付ファイルオブジェクト(Attachment)のファイルを出力します。
batch_Document.bat download_Document.txt ドキュメントオブジェクト(Document)のファイルを出力します。
batch_EventLogFile.bat download_Eventlogfile.txt イベントログを使うにはライセンスが必要です。
Event Log Files(Eventlogfile)のファイルを出力します。

 スクリプトファイルで、SOQLの条件は指定していないので、必要に応じて条件を指定してください。以下は添付ファイルへのSOQLを直近10日で更新されたという条件を追加した例になります。

    //3.バイナリデータを取得するSOQL
    String soql = "select Id, Name, Body from Attachment Where LastModifiedDate = LAST_N_DAYS:10";

 

Salesforceへの接続情報や通信設定は、各スクリプトの次の箇所を修正してください。

    //1.通信情報
    String proxyhost = null;
    Integer proxyport = null;
    String ntlmdomain = null;

    String proxyuser = null;
    String proxypassword = null;

    //2.Salesforce接続情報
    String sfendpoint = "https://test.salesforce.com/services/Soap/u/40.0";
    String sfusername = "sample@username";
    String sfpassword = "samplepassword";

 

 柔軟にテキストを修正できるという点でbeanshellの良さがあるなーと思いました。

 

Java: BeanShellが使いやすい

Javaスクリプトを実行する仕組みは色々ありますが、Javaコードがほぼそのまま実行できる点でbeanshellはとても使いやすいなと感じています。
(でも、ジェネリクスや、可変長引数は対応してないので、うっかり書いてしまうとエラーの解決に時間がかかります)

私は、ある程度までは、IDEでがりがり書いた後にbeanshellでの実行するようにテキストファイルに書くというスタイルをとっています。

windowsDOSバッチなどで、javaのライブラリが使えれば楽なのになーという時が、beanshellの出番です。

普通にコンパイルしたクラスで実行してもいいのですが、コンパイルが不要でテキストがそのまま実行できるので、修正・変更がとても簡単です。

 

もし、rhinoなどと迷っているなら、beanshellをお勧めします。

次以降に、beanshellを使ったSalesforceAPI操作のツールを紹介したいと思います。

Salesforce: コマンドラインのメタデータのエクスポートツールのAPIバージョンをあげました(apiver40.0)

Summer'17(apiver40.0)のエクスポートツールはこちらです。

 

api39.0のものや、使い方は前回の記事を参照ください。

 

crmprogrammer38.hatenablog.com

 

修正履歴

2017/7/24 CustomFeedFilterのダウンロード時にエラーとなる事象の対応を行いました。具体的には、CustomFeedFilterはワイルドカード指定でリクエストするように変更しています。

Java: wscでSalesforce APIを使用する

まずはサンプルコード

    ConnectorConfig connectorConfig = new ConnectorConfig();
String soapEndpoint = "https://login.salesforce.com/services/Soap/u/39.0";
connectorConfig.setAuthEndpoint(soapEndpoint);
connectorConfig.setManualLogin(true);
connectorConfig.setCompression(true);
connectorConfig.setConnectionTimeout(120000);

//httpプロキシを指定する
{
connectorConfig.setProxy("samplehost", 9999);
ProxyUserPasswordConfig.setProxyUserPassword("sampleproxyuser", "sampleproxypasword");
}

PartnerConnection soapBinding = Connector.newConnection(connectorConfig);
LoginResult lr = soapBinding.login("sampleuser@sample.username", "samplepassword");
soapBinding.setSessionHeader(lr.getSessionId());
connectorConfig.setServiceEndpoint(lr.getServerUrl());

System.out.println(soapBinding.getServerTimestamp().getTimestamp());

httpproxyのユーザ、パスワードは「PasswordAuthentication」を使うため上記で次のクラスを使っています。(wsimportの時と同様です)

import java.net.Authenticator;
import java.net.PasswordAuthentication;

public class ProxyUserPasswordConfig extends Authenticator {

private String user;
private String password;

private ProxyUserPasswordConfig(String proxyuser, String proxypassword){
user = proxyuser;
password = proxypassword;
}

public static void setProxyUserPassword(String proxyuser, String proxypassword){
Authenticator.setDefault(new ProxyUserPasswordConfig(proxyuser,proxypassword));
}
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(user, password.toCharArray());
}
}

コードの生成とライブラリの作成

wscのライブラリをclasspathに指定し次のコマンドを使います。jarまで自動で作成してくれます。jarにはソースコードも含まれます。

java -DcompileTarget=1.8  -classpath ..\lib\* com.sforce.ws.tools.wsdlc partner.wsdl partner.jar
java -DcompileTarget=1.8 -classpath ..\lib\* com.sforce.ws.tools.wsdlc metadata.wsdl metadata.jar

httpproxyの設定

コード内で指定となっています。

      connectorConfig.setProxy("samplehost", 9999);
ProxyUserPasswordConfig.setProxyUserPassword("sampleproxyuser", "sampleproxypasword");

エンドポイントの設定

ConnectorConfigで指定となります。

    ConnectorConfig connectorConfig = new ConnectorConfig();
String soapEndpoint = "https://login.salesforce.com/services/Soap/u/39.0";
connectorConfig.setAuthEndpoint(soapEndpoint);

セッションIDと、インスタンスURLのセット

ここも、エンドポイントと同様に、ConnectorConfigで指定します。

    soapBinding.setSessionHeader(lr.getSessionId());
connectorConfig.setServiceEndpoint(lr.getServerUrl());

これで上記コードのsoapBindingでSOAP APIを使用できます。

Salesforce専用ライブラリであり、他のライブラリに比べとても簡潔なコードになります。

また、スレッドセーフな設計です。(他のライブラリは1つのスタブインスタンスを複数スレッドで使うことができません)

 

ただし、注意事項として、insert/update/upsertで、ライブラリ側で項目にセットした値の型をチェックします。

他のライブラリは項目にセットするのは文字型であり、

  • 日付型はyyyy-MM-ddの形式
  • 日付/時間型はyyyy-MM-dd'Y'HH:mm:ss.000Z形式
  • チェックボックス型はtrue/false
  • バイナリ型はbase64エンコードされた文字列
  • 数値型は、数値として扱える文字列(指数表現もok)

なのに対して、wscは

  • 日付型はDate
  • 日付/時間型はCalendar
  • チェックボックス型はBoolean
  • バイナリ型はbyte[]
  • int型は、Integer (なぜか他の数値項目は、数値として扱える文字列でok)

の制限があります。

 

他のライブラリでは、上記型の値が不正だった場合、APIコール時に原因追求が困難なエラーがでます。が、wscはライブラリ側であえてエラー制御を実装しているということだと思います。

 

Java: apache cxfでSalesforce APIを使用する

まずはサンプルコード

    URL wsdlurl = Soap.class.getClassLoader().getResource("/partner.wsdl");
Soap soapBinding = new SforceService(wsdlurl).getSoap();

BindingProvider bp = (BindingProvider)soapBinding;
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,"https://login.salesforce.com/services/Soap/u/38.0");

Client client = ClientProxy.getClient(bp);

client.getInInterceptors().add(new GZIPInInterceptor());
client.getOutInterceptors().add(new GZIPOutInterceptor());

HTTPConduit conduit = (HTTPConduit)client.getConduit();
HTTPClientPolicy policy = new HTTPClientPolicy();
policy.setAllowChunking(true);
policy.setConnectionTimeout(120000);
policy.setProxyServer("sampleproxyhost");
policy.setProxyServerType(ProxyServerType.HTTP);
policy.setProxyServerPort(9999);

ProxyAuthorizationPolicy authpolicy = new ProxyAuthorizationPolicy();
authpolicy.setUserName("sampleproxyuser");
authpolicy.setPassword("samplepassword");
conduit.setProxyAuthorization(authpolicy);

conduit.setClient(policy);


LoginResult loginResult = soapBinding.login("sampleuser@sample.username", "samplepassword", null, null);


bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,loginResult.getServerUrl());

SessionHeader sh = new SessionHeader();
String sessionId = loginResult.getSessionId();
sh.setSessionId(sessionId);

System.out.println(soapBinding.getServerTimestamp(sh, null, null).getTimestamp());

コードの生成とライブラリの作成

ライブラリ付属のwsdl2javaコマンドを使います。jarまで自動で作成してくれます。

set JAVA_HOME=javahomeのパス

wsdl2java.bat -d partner -b jaxb.xml -exsh true -autoNameResolution -clientjar partner.jar partner.wsdl
wsdl2java.bat -d metadata -b jaxb.xml -exsh true -autoNameResolution -clientjar metadata.jar metadata.wsdl

_jaxb.xmlというのを上記コマンドで指定していますが、_jaxb.xmlの中身は次のテキストです。 typesafeEnumMaxMembersの上限エラーになったのでサイズを増やしています。(wsimportの時と同様です)

<jaxb:bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jaxb:extensionBindingPrefixes="xjc"
jaxb:version="1.0">
<jaxb:globalBindings typesafeEnumMaxMembers="2000">
<xjc:serializable/>
</jaxb:globalBindings>
</jaxb:bindings>

httpproxyの設定

コード内で指定となっています。

    Client client = ClientProxy.getClient(bp);

HTTPConduit conduit = (HTTPConduit)client.getConduit();
HTTPClientPolicy policy = new HTTPClientPolicy();
policy.setProxyServer("sampleproxyhost");
policy.setProxyServerType(ProxyServerType.HTTP);
policy.setProxyServerPort(9999);

ProxyAuthorizationPolicy authpolicy = new ProxyAuthorizationPolicy();
authpolicy.setUserName("sampleproxyuser");
authpolicy.setPassword("samplepassword");
conduit.setProxyAuthorization(authpolicy);

conduit.setClient(policy);

エンドポイントの設定

BindingProviderを使うことで指定します。

    URL wsdlurl = Soap.class.getClassLoader().getResource("/partner.wsdl");
Soap soapBinding = new SforceService(wsdlurl).getSoap();

BindingProvider bp = (BindingProvider)soapBinding;
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,"https://login.salesforce.com/services/Soap/u/38.0");

セッションIDと、インスタンスURLのセット

ここも、エンドポイントと同様に、BindingProviderを使います。

セッションIDは、SOAPHeaderにセットしておくのではなく、APIを呼び出す際に引数で指定します。

        bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,loginResult.getServerUrl());

SessionHeader sh = new SessionHeader();
String sessionId = loginResult.getSessionId();
sh.setSessionId(sessionId);

これで上記コードのsoapBindingでSOAP APIを使用できます。

cxf3.Xを使うとデータバインディングがとても遅かったので、cxf2.7がお勧めです。