与Microsoft Translator API连接时SSLException

时间:2015-04-17 09:25:51

标签: java android microsoft-translator

我一直在尝试将我的Android应用与Microsoft Translator API连接,我已经在Windows Azure Marketplace中注册了我的应用。但是当我运行我的应用程序时,我在打开应用程序时一直遇到IOException。

04-17 21:18:15.661: E/TranslateTask(274): IOException
04-17 21:18:15.661: E/TranslateTask(274): javax.net.ssl.SSLException: Not trusted server certificate
04-17 21:18:15.661: E/TranslateTask(274):   at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:371)
04-17 21:18:15.661: E/TranslateTask(274):   at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.getSecureSocket(HttpConnection.java:168)
04-17 21:18:15.661: E/TranslateTask(274):   at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:399)
04-17 21:18:15.661: E/TranslateTask(274):   at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:147)
04-17 21:18:15.661: E/TranslateTask(274):   at ac.lk.iit.androidtranslatorproject.TranslateActivity$GetAccessTokenTask.doInBackground(TranslateActivity.java:212)
04-17 21:18:15.661: E/TranslateTask(274):   at ac.lk.iit.androidtranslatorproject.TranslateActivity$GetAccessTokenTask.doInBackground(TranslateActivity.java:1)
04-17 21:18:15.661: E/TranslateTask(274):   at android.os.AsyncTask$2.call(AsyncTask.java:185)
04-17 21:18:15.661: E/TranslateTask(274):   at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
04-17 21:18:15.661: E/TranslateTask(274):   at java.util.concurrent.FutureTask.run(FutureTask.java:137)
04-17 21:18:15.661: E/TranslateTask(274):   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
04-17 21:18:15.661: E/TranslateTask(274):   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
04-17 21:18:15.661: E/TranslateTask(274):   at java.lang.Thread.run(Thread.java:1096)
04-17 21:18:15.661: E/TranslateTask(274): Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: TrustAnchor for CertPath not found.
04-17 21:18:15.661: E/TranslateTask(274):   at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:168)
04-17 21:18:15.661: E/TranslateTask(274):   at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:366)
04-17 21:18:15.661: E/TranslateTask(274):   ... 11 more
04-17 21:18:15.661: E/TranslateTask(274): Caused by: java.security.cert.CertPathValidatorException: TrustAnchor for CertPath not found.
04-17 21:18:15.661: E/TranslateTask(274):   at org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:149)
04-17 21:18:15.661: E/TranslateTask(274):   at java.security.cert.CertPathValidator.validate(CertPathValidator.java:202)
04-17 21:18:15.661: E/TranslateTask(274):   at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:164)
04-17 21:18:15.661: E/TranslateTask(274):   ... 12 more

此外,以下是该应用程序的相关文件。

TranslateActivity.java

package ac.lk.iit.androidtranslatorproject;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;

public class TranslateActivity extends Activity {
    private static final String TAG = "TranslateTask";
    private Spinner fromSpinner;
    private Spinner toSpinner;
    private EditText origText;
    private TextView transText;
    private Button transButton;
    private String fromLang;
    private String toLang;
    private TextWatcher textWatcher;
    private OnItemSelectedListener itemListener;
    private OnClickListener buttonListener;
    // needed to make translate requests to Microsoft
    private String accessToken;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_translate);
        findViews();
        setAdapters();
        setListeners();
        // get the access token from Microsoft
        new GetAccessTokenTask().execute();
    }

    private void findViews() {
        fromSpinner = (Spinner) findViewById(R.id.from_language);
        toSpinner = (Spinner) findViewById(R.id.to_language);
        origText = (EditText) findViewById(R.id.original_text);
        transText = (TextView) findViewById(R.id.translated_text);
        transButton = (Button) findViewById(R.id.translate_button);
    }

    /** Define data source for the spinners */
    private void setAdapters() {
        // Spinner list comes from a resource,
        // Spinner user interface uses standard layouts
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,R.array.languages,android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        fromSpinner.setAdapter(adapter);
        toSpinner.setAdapter(adapter);
        // Automatically select two spinner items
        fromSpinner.setSelection(8); // English (en)
        toSpinner.setSelection(25); // Spanish (es)
    }

    private void setListeners() {
        textWatcher = new TextWatcher() {
            public void beforeTextChanged(CharSequence s,int start, int count,int after) {
            }

            public void onTextChanged(CharSequence s,int start, int before,int count) {
                /*doTranslate2(origText.getText().toString().trim(),fromLang, toLang); */
            }

            public void afterTextChanged(Editable s) {
            }};
            origText.addTextChangedListener(textWatcher);
            itemListener = new OnItemSelectedListener() {
                public void onItemSelected(AdapterView parent, View v,int position, long id) {
                fromLang = getLang(fromSpinner);
                toLang = getLang(toSpinner);
                if (accessToken != null)
                    doTranslate2(origText.getText().toString().trim(), fromLang, toLang);
                }
                public void onNothingSelected(AdapterView parent) {
                    /* Do nothing */
                }};
                fromSpinner.setOnItemSelectedListener(itemListener);
                toSpinner.setOnItemSelectedListener(itemListener);
                buttonListener = new OnClickListener() {
                    public void onClick(View v) {
                    if (accessToken != null)
                        System.out.println(accessToken);
                        doTranslate2(origText.getText().toString().trim(), fromLang, toLang);
                    }};
                    transButton.setOnClickListener(buttonListener);
                }

                /** Extract the language code from the current spinner item */
            private String getLang(Spinner spinner) {
                String result = spinner.getSelectedItem().toString();
                int lparen = result.indexOf('(');
                int rparen = result.indexOf(')');
                result = result.substring(lparen + 1, rparen);
                return result;
            }

            private void doTranslate2(String original,String from, String to) {
                if (accessToken != null)
                    new TranslationTask().execute(original, from, to);
            }

            private class TranslationTask extends AsyncTask<String,Void,String> {
                protected void onPostExecute(String translation) {
                    transText.setText(translation);
                }
                protected String doInBackground(String... s) {
                    HttpURLConnection con2 = null;
                    String result = getResources().getString(
                    R.string.translation_error);
                    String original = s[0];
                    String from = s[1];
                    String to = s[2];
                    try {
                        // Read results from the query
                        BufferedReader reader;
                        String uri = "http://api.microsofttranslator.com" + "/v2/Http.svc/Translate?text=" + URLEncoder.encode(original) +"&from=" + from + "&to=" + to;
                        URL url_translate = new URL(uri);
                        String authToken = "Bearer" + " " + accessToken;
                        con2 = (HttpURLConnection) url_translate.
                        openConnection();
                        con2.setRequestProperty("Authorization", authToken);
                        con2.setDoInput(true);
                        con2.setReadTimeout(10000 /* milliseconds */);
                        con2.setConnectTimeout(15000 /* milliseconds */);
                        reader = new BufferedReader(new InputStreamReader(
                        con2.getInputStream(), "UTF-8"));
                        String translated_xml = reader.readLine();
                        reader.close();
                        /* translated_xml now contains the following XML:
                        <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Hola</string> */
                        // parse the XML returned
                        DocumentBuilder builder = DocumentBuilderFactory.
                        newInstance().newDocumentBuilder();
                        Document doc = builder.parse(new InputSource(new StringReader(translated_xml)));
                        NodeList node_list = doc.getElementsByTagName("string");
                        NodeList l = node_list.item(0).getChildNodes();
                        Node node;
                        String translated = null;
                        if (l != null && l.getLength() > 0) {
                            node = l.item(0);
                            translated = node.getNodeValue();
                        }
                        if (translated != null)
                            result = translated;
                        } catch (IOException e) {
                            Log.e(TAG, "IOException", e);
                        } catch (SAXException e) {
                            e.printStackTrace();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        finally {
                            if (con2 != null) {
                                con2.disconnect();
                            }
                        }
                        return result;
                    }
                }

            private class GetAccessTokenTask extends AsyncTask<Void, Void, String> {
                protected void onPostExecute(String access_token) {
                    accessToken = access_token;
                }
                protected String doInBackground(Void... v) {
                    String result = null;
                    HttpURLConnection con = null;
                    String clientID = "<client id>";
                    String clientSecret = "<client secret>";
                    String strTranslatorAccessURI ="https://datamarket.accesscontrol.windows.net/v2/OAuth2-13";
                    String strRequestDetails = "grant_type=" + "client_credentials&client_id=" + URLEncoder.encode(clientID) + "&client_secret="+ URLEncoder.encode(clientSecret) + "&scope=http://api.microsofttranslator.com";

                    try {
                        URL url = new URL(strTranslatorAccessURI);
                        con = (HttpURLConnection) url.openConnection();
                        con.setReadTimeout(10000 /* milliseconds */);
                        con.setConnectTimeout(15000 /* milliseconds */);
                        con.setRequestMethod("POST");
                        con.setDoInput(true);
                        con.setDoOutput(true);
                        con.setChunkedStreamingMode(0);
                        // Start the query
                        con.connect();
                        OutputStream out = new BufferedOutputStream(con.getOutputStream());
                        out.write(strRequestDetails.getBytes());
                        out.flush();
                        // Read results from the query
                        BufferedReader reader = new BufferedReader(
                        new InputStreamReader(con.getInputStream(), "UTF-8"));
                        String payload = reader.readLine();
                        reader.close();
                        out.close();
                        /* payload now contains JSON attribute value pairs:
                        {"token_type":"http://schemas.xmlsoap.org/ws/2009/
                        11/swt-token-profile-1.0","access_token":"....",
                        "expires_in":"600","scope":
                        "http://api.microsofttranslator.com"} */
                        // Parse to get the access token
                        JSONObject jsonObject = new JSONObject(payload);
                        result = jsonObject.getString("access_token");
                    } catch (IOException e) {
                        Log.e(TAG, "IOException", e);
                    } catch (JSONException e) {
                        Log.e(TAG, "JSONException", e);
                    } finally {
                        if (con != null) {
                            con.disconnect();
                        }
                    }
                    return result;
                }
            }
}

我没有提到客户端ID和秘密但是错误似乎是从doInBackground方法中抛出的,并且确切地说是方法调用connect()的点。

以下是活动的布局页面。

activity_translate.xml

<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TableLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:stretchColumns="1"
        android:padding="10dip">
        <TableRow>
            <TextView android:text="@string/from_text" />
            <Spinner android:id="@+id/from_language" />
        </TableRow>
        <EditText
            android:id="@+id/original_text"
            android:hint="@string/original_hint"
            android:padding="10dip"
            android:textSize="18sp" />
        <TableRow>
            <TextView android:text="@string/to_text" />
            <Spinner android:id="@+id/to_language" />
        </TableRow>
        <TextView
            android:id="@+id/translated_text"
            android:padding="10dip"
            android:textSize="18sp" />
        <Button
            android:id="@+id/translate_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Translate"
            android:layout_gravity="center" />
    </TableLayout>
</ScrollView>

我还确保在应用清单文件中启用了使用互联网的许可。

如果有人能帮助我找到解决这个问题的方法,我将不胜感激,因为这对我来说是一个全新的领域,如果上述错误的原因也能得到清楚解释,我将不胜感激。请原谅我因为在我刚接触这个研究领域之前提到的任何错误。

1 个答案:

答案 0 :(得分:0)

我不知道第三方库是否可以在这种情况下提供帮助,但使用OkHTTP库帮助我修复了一些很少出现在我的应用程序中的SSL证书的错误。 https://github.com/square/okhttp