この文章は Salesforce 機械翻訳システムを使用して翻訳されました。詳細はこちらをご参照ください。
英語に切り替える

ステップ 3: Java サンプルコードの説明

WSDL ファイルをインポートすると、メタデータ API を使用するクライアントアプリケーションを構築できます。このサンプルは、独自のコードを記述するための出発点として適しています。

サンプルを実行する前に、プロジェクトとコードを次のように変更します。

  1. WSC JAR、その連動関係、および WSDL から生成した JAR ファイルを含めます。

    WSC には他の連動関係がありますが、次のサンプルでは Rhino (js-1.7R2.jar) のみが必要です。これは、mvnrepository.com/artifact/rhino/js からダウンロードできます。

    メモ

  2. 自分のユーザ名とパスワードを使って、MetadataLoginUtil.login() メソッドの USERNAME 変数と PASSWORD 変数を更新します。現在の IP アドレスが組織の信頼済み IP 範囲内にない場合は、セキュリティトークンをパスワードに追加する必要があります。
  3. Sandbox を使用している場合は、必ずログイン URL を変更してください。

ログインユーティリティ

Java ユーザは、ConnectorConfig を使用して、Enterprise API、Partner API、および Metadata SOAP API に接続できます。MetadataLoginUtilConnectorConfig オブジェクトを作成し、Enterprise WSDL の login メソッドを使用してログインします。次に、sessionIdmetadataServerUrl を取得して ConnectorConfig を作成し、メタデータ API のエンドポイントに接続します。ConnectorConfig は WSC で定義されています。

MetadataLoginUtil クラスは、サンプルの他の部分からログインコードを抽象化するため、Salesforce API ごとに変更を行わずにこのコードの一部を再利用できます。

1import com.sforce.soap.enterprise.EnterpriseConnection;
2import com.sforce.soap.enterprise.LoginResult;
3import com.sforce.soap.metadata.MetadataConnection;
4import com.sforce.ws.ConnectionException;
5import com.sforce.ws.ConnectorConfig;
6
7/**
8 * Login utility.
9 */
10public class MetadataLoginUtil {
11
12    public static MetadataConnection login() throws ConnectionException {
13        final String USERNAME = "user@company.com";
14        // This is only a sample. Hard coding passwords in source files is a bad practice.
15        final String PASSWORD = "password"; 
16        final String URL = "https://login.salesforce.com/services/Soap/c/38.0";
17        final LoginResult loginResult = loginToSalesforce(USERNAME, PASSWORD, URL);
18        return createMetadataConnection(loginResult);
19    }
20
21    private static MetadataConnection createMetadataConnection(
22            final LoginResult loginResult) throws ConnectionException {
23        final ConnectorConfig config = new ConnectorConfig();
24        config.setServiceEndpoint(loginResult.getMetadataServerUrl());
25        config.setSessionId(loginResult.getSessionId());
26        return new MetadataConnection(config);
27    }
28
29    private static LoginResult loginToSalesforce(
30            final String username,
31            final String password,
32            final String loginUrl) throws ConnectionException {
33        final ConnectorConfig config = new ConnectorConfig();
34        config.setAuthEndpoint(loginUrl);
35        config.setServiceEndpoint(loginUrl);
36        config.setManualLogin(true);
37        return (new EnterpriseConnection(config)).login(username, password);
38    }
39}

この例では、ユーザとパスワードの認証を使用してセッション ID が取得され、セッション ID が Metadata API へのコールを行うために使用されます。または、OAuth 認証を使用することもできます。OAuth で Salesforce に認証した後、返されたアクセストークンをセッション ID の代わりに渡します。たとえば、アクセストークンを ConnectorConfigsetSessionId() コールに渡します。Salesforce で OAuth 認証を使用する方法についての詳細は、Salesforce ヘルプの 「Authenticating Apps with OAuth (OAuth によるアプリケーションの認証)」 を参照してください。

メモ

ファイルベース開発用の Java のサンプルコード

サンプルコードは、ログインユーティリティを使用してログインします。次に、取得、リリース、および終了のメニューを表示します。

retrieve() コールおよび deploy() コールは両方とも components.zip という名前の .zip ファイルを処理します。retrieve() コールは組織のコンポーネントを components.zip に取得し、deploy() コールは components.zip のコンポーネントを組織にリリースします。コンピュータにサンプルを保存して実行する場合は、後でリリースできる components.zip ファイルを含めることができるように、まず取得オプションを実行します。retrieve コールの後、サンプルは、操作が完了するまで checkRetrieveStatus() コールをループします。同様に、deploy コールの後、サンプルは、操作が完了するまで checkDeployStatus() チェックをループします。

retrieve() コールは、マニフェストファイルを使用して組織から取得するコンポーネントを決定します。package.xml マニフェストファイルのサンプルは次のとおりです。マニフェストファイルの構造についての詳細は、「Zip ファイルの使用」を参照してください。このサンプルでは、マニフェストファイルはすべてのカスタムオブジェクト、カスタムタブ、およびページレイアウトを取得します。

1<?xml version="1.0" encoding="UTF-8"?>
2<Package xmlns="http://soap.sforce.com/2006/04/metadata">
3    <types>
4        <members>*</members>
5        <name>CustomObject</name>
6    </types>
7    <types>
8        <members>*</members>
9        <name>CustomTab</name>
10    </types>
11    <types>
12        <members>*</members>
13        <name>Layout</name>
14    </types>
15    <version>38.0</version>
16</Package>

API コールに続く、エラー処理コードに注意してください。

このサンプルでは、API バージョン 34.0 以降が必要です。

メモ

1import java.io.*;
2import java.nio.channels.Channels;
3import java.nio.channels.FileChannel;
4import java.nio.channels.ReadableByteChannel;
5import java.rmi.RemoteException;
6import java.util.*;
7
8import javax.xml.parsers.*;
9
10import org.w3c.dom.*;
11import org.xml.sax.SAXException;
12
13import com.sforce.soap.metadata.*;
14
15/**
16 * Sample that logs in and shows a menu of retrieve and deploy metadata options.
17 */
18public class FileBasedDeployAndRetrieve {
19
20    private MetadataConnection metadataConnection;
21
22    private static final String ZIP_FILE = "components.zip";
23
24    // manifest file that controls which components get retrieved
25    private static final String MANIFEST_FILE = "package.xml";
26
27    private static final double API_VERSION = 29.0;
28
29    // one second in milliseconds
30    private static final long ONE_SECOND = 1000;
31
32    // maximum number of attempts to deploy the zip file
33    private static final int MAX_NUM_POLL_REQUESTS = 50;
34
35    private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
36
37    public static void main(String[] args) throws Exception {
38        FileBasedDeployAndRetrieve sample = new FileBasedDeployAndRetrieve();
39        sample.run();
40    }
41
42    public FileBasedDeployAndRetrieve() {
43    }
44
45    private void run() throws Exception {
46        this.metadataConnection = MetadataLoginUtil.login();
47
48        // Show the options to retrieve or deploy until user exits
49        String choice = getUsersChoice();
50        while (choice != null && !choice.equals("99")) {
51            if (choice.equals("1")) {
52                retrieveZip();
53            } else if (choice.equals("2")) {
54                deployZip();
55            } else {
56                break;
57            }
58            // show the options again
59            choice = getUsersChoice();
60        }
61    }
62
63    /*
64     * Utility method to present options to retrieve or deploy.
65     */
66    private String getUsersChoice() throws IOException {
67        System.out.println(" 1: Retrieve");
68        System.out.println(" 2: Deploy");
69        System.out.println("99: Exit");
70        System.out.println();
71        System.out.print("Enter 1 to retrieve, 2 to deploy, or 99 to exit: ");
72        // wait for the user input.
73        String choice = reader.readLine();
74        return choice != null ? choice.trim() : "";
75    }
76
77    private void deployZip() throws Exception {
78        byte zipBytes[] = readZipFile();
79        DeployOptions deployOptions = new DeployOptions();
80        deployOptions.setPerformRetrieve(false);
81        deployOptions.setRollbackOnError(true);
82        AsyncResult asyncResult = metadataConnection.deploy(zipBytes, deployOptions);
83        DeployResult result = waitForDeployCompletion(asyncResult.getId());
84        if (!result.isSuccess()) {
85            printErrors(result, "Final list of failures:\n");
86            throw new Exception("The files were not successfully deployed");
87        }
88        System.out.println("The file " + ZIP_FILE + " was successfully deployed\n");
89    }
90
91    /*
92    * Read the zip file contents into a byte array.
93    */
94    private byte[] readZipFile() throws Exception {
95        byte[] result = null;
96        // We assume here that you have a deploy.zip file.
97        // See the retrieve sample for how to retrieve a zip file.
98        File zipFile = new File(ZIP_FILE);
99        if (!zipFile.exists() || !zipFile.isFile()) {
100            throw new Exception("Cannot find the zip file for deploy() on path:"
101                + zipFile.getAbsolutePath());
102        }
103
104        FileInputStream fileInputStream = new FileInputStream(zipFile);
105        try {
106            ByteArrayOutputStream bos = new ByteArrayOutputStream();
107            byte[] buffer = new byte[4096];
108            int bytesRead = 0;
109            while (-1 != (bytesRead = fileInputStream.read(buffer))) {
110                bos.write(buffer, 0, bytesRead);
111            }
112
113            result = bos.toByteArray();
114        } finally {
115            fileInputStream.close();
116        }
117        return result;
118    }
119
120    /*
121    * Print out any errors, if any, related to the deploy.
122    * @param result - DeployResult
123    */
124    private void printErrors(DeployResult result, String messageHeader) {
125        DeployDetails details = result.getDetails();
126        StringBuilder stringBuilder = new StringBuilder();
127        if (details != null) {
128            DeployMessage[] componentFailures = details.getComponentFailures();
129            for (DeployMessage failure : componentFailures) {
130                String loc = "(" + failure.getLineNumber() + ", " + failure.getColumnNumber();
131                if (loc.length() == 0 && !failure.getFileName().equals(failure.getFullName()))
132                {
133                    loc = "(" + failure.getFullName() + ")";
134                }
135                stringBuilder.append(failure.getFileName() + loc + ":" 
136                    + failure.getProblem()).append('\n');
137            }
138            RunTestsResult rtr = details.getRunTestResult();
139            if (rtr.getFailures() != null) {
140                for (RunTestFailure failure : rtr.getFailures()) {
141                    String n = (failure.getNamespace() == null ? "" :
142                        (failure.getNamespace() + ".")) + failure.getName();
143                    stringBuilder.append("Test failure, method: " + n + "." +
144                            failure.getMethodName() + " -- " + failure.getMessage() + 
145                            " stack " + failure.getStackTrace() + "\n\n");
146                }
147            }
148            if (rtr.getCodeCoverageWarnings() != null) {
149                for (CodeCoverageWarning ccw : rtr.getCodeCoverageWarnings()) {
150                    stringBuilder.append("Code coverage issue");
151                    if (ccw.getName() != null) {
152                        String n = (ccw.getNamespace() == null ? "" :
153                        (ccw.getNamespace() + ".")) + ccw.getName();
154                        stringBuilder.append(", class: " + n);
155                    }
156                    stringBuilder.append(" -- " + ccw.getMessage() + "\n");
157                }
158            }
159        }
160        if (stringBuilder.length() > 0) {
161            stringBuilder.insert(0, messageHeader);
162            System.out.println(stringBuilder.toString());
163        }
164    }
165    
166
167    private void retrieveZip() throws Exception {
168        RetrieveRequest retrieveRequest = new RetrieveRequest();
169        // The version in package.xml overrides the version in RetrieveRequest
170        retrieveRequest.setApiVersion(API_VERSION);
171        setUnpackaged(retrieveRequest);
172
173        AsyncResult asyncResult = metadataConnection.retrieve(retrieveRequest);
174        RetrieveResult result = waitForRetrieveCompletion(asyncResult);
175
176        if (result.getStatus() == RetrieveStatus.Failed) {
177            throw new Exception(result.getErrorStatusCode() + " msg: " +
178                    result.getErrorMessage());
179        } else if (result.getStatus() == RetrieveStatus.Succeeded) {  
180	        // Print out any warning messages
181	        StringBuilder stringBuilder = new StringBuilder();
182	        if (result.getMessages() != null) {
183	            for (RetrieveMessage rm : result.getMessages()) {
184	                stringBuilder.append(rm.getFileName() + " - " + rm.getProblem() + "\n");
185	            }
186	        }
187	        if (stringBuilder.length() > 0) {
188	            System.out.println("Retrieve warnings:\n" + stringBuilder);
189	        }
190	
191	        System.out.println("Writing results to zip file");
192	        File resultsFile = new File(ZIP_FILE);
193	        FileOutputStream os = new FileOutputStream(resultsFile);
194	
195	        try {
196	            os.write(result.getZipFile());
197	        } finally {
198	            os.close();
199	        }
200        }
201    }
202
203    private DeployResult waitForDeployCompletion(String asyncResultId) throws Exception {
204        int poll = 0;
205        long waitTimeMilliSecs = ONE_SECOND;
206        DeployResult deployResult;
207        boolean fetchDetails;
208        do {
209            Thread.sleep(waitTimeMilliSecs);
210            // double the wait time for the next iteration
211
212            waitTimeMilliSecs *= 2;
213            if (poll++ > MAX_NUM_POLL_REQUESTS) {
214                throw new Exception(
215                    "Request timed out. If this is a large set of metadata components, " +
216                    "ensure that MAX_NUM_POLL_REQUESTS is sufficient.");
217            }
218            // Fetch in-progress details once for every 3 polls
219            fetchDetails = (poll % 3 == 0);
220
221            deployResult = metadataConnection.checkDeployStatus(asyncResultId, fetchDetails);
222            System.out.println("Status is: " + deployResult.getStatus());
223            if (!deployResult.isDone() && fetchDetails) {
224                printErrors(deployResult, "Failures for deployment in progress:\n");
225            }
226        }
227        while (!deployResult.isDone());
228
229        if (!deployResult.isSuccess() && deployResult.getErrorStatusCode() != null) {
230            throw new Exception(deployResult.getErrorStatusCode() + " msg: " +
231                    deployResult.getErrorMessage());
232        }
233        
234        if (!fetchDetails) {
235            // Get the final result with details if we didn't do it in the last attempt.
236            deployResult = metadataConnection.checkDeployStatus(asyncResultId, true);
237        }
238        
239        return deployResult;
240    }
241
242    private RetrieveResult waitForRetrieveCompletion(AsyncResult asyncResult) throws Exception {
243    	// Wait for the retrieve to complete
244        int poll = 0;
245        long waitTimeMilliSecs = ONE_SECOND;
246        String asyncResultId = asyncResult.getId();
247        RetrieveResult result = null;
248        do {
249            Thread.sleep(waitTimeMilliSecs);
250            // Double the wait time for the next iteration
251            waitTimeMilliSecs *= 2;
252            if (poll++ > MAX_NUM_POLL_REQUESTS) {
253                throw new Exception("Request timed out.  If this is a large set " +
254                "of metadata components, check that the time allowed " +
255                "by MAX_NUM_POLL_REQUESTS is sufficient.");
256            }
257            result = metadataConnection.checkRetrieveStatus(
258                    asyncResultId, true);
259            System.out.println("Retrieve Status: " + result.getStatus());
260        } while (!result.isDone());         
261
262        return result;
263    }
264
265    private void setUnpackaged(RetrieveRequest request) throws Exception {
266        // Edit the path, if necessary, if your package.xml file is located elsewhere
267        File unpackedManifest = new File(MANIFEST_FILE);
268        System.out.println("Manifest file: " + unpackedManifest.getAbsolutePath());
269
270        if (!unpackedManifest.exists() || !unpackedManifest.isFile()) {
271            throw new Exception("Should provide a valid retrieve manifest " +
272                "for unpackaged content. Looking for " +
273                unpackedManifest.getAbsolutePath());
274        }
275
276        // Note that we use the fully quualified class name because
277        // of a collision with the java.lang.Package class
278        com.sforce.soap.metadata.Package p = parsePackageManifest(unpackedManifest);
279        request.setUnpackaged(p);
280    }
281
282    private com.sforce.soap.metadata.Package parsePackageManifest(File file)
283            throws ParserConfigurationException, IOException, SAXException {
284        com.sforce.soap.metadata.Package packageManifest = null;
285        List<PackageTypeMembers> listPackageTypes = new ArrayList<PackageTypeMembers>();
286        DocumentBuilder db =
287                DocumentBuilderFactory.newInstance().newDocumentBuilder();
288        InputStream inputStream = new FileInputStream(file);
289        Element d = db.parse(inputStream).getDocumentElement();
290        for (Node c = d.getFirstChild(); c != null; c = c.getNextSibling()) {
291            if (c instanceof Element) {
292                Element ce = (Element) c;
293                NodeList nodeList = ce.getElementsByTagName("name");
294                if (nodeList.getLength() == 0) {
295                    continue;
296                }
297                String name = nodeList.item(0).getTextContent();
298                NodeList m = ce.getElementsByTagName("members");
299                List<String> members = new ArrayList<String>();
300                for (int i = 0; i < m.getLength(); i++) {
301                    Node mm = m.item(i);
302                    members.add(mm.getTextContent());
303                }
304                PackageTypeMembers packageTypes = new PackageTypeMembers();
305                packageTypes.setName(name);
306                packageTypes.setMembers(members.toArray(new String[members.size()]));
307                listPackageTypes.add(packageTypes);
308            }
309        }
310        packageManifest = new com.sforce.soap.metadata.Package();
311        PackageTypeMembers[] packageTypesArray =
312                new PackageTypeMembers[listPackageTypes.size()];
313        packageManifest.setTypes(listPackageTypes.toArray(packageTypesArray));
314        packageManifest.setVersion(API_VERSION + "");
315        return packageManifest;
316    }
317}