using google map geocoding service at service side - google-maps

i wrote the following code to get the coordinate of a address
package test;
import java.net.HttpURLConnection;
import java.net.URL;
import sun.net.www.content.text.PlainTextInputStream;
public class a{
public static void main(String[] arg) throws Exception{
String address = "台北市信義路五段七號101樓";
// 查詢經緯度
String output = "csv";
String key = "";
String url = "http://maps.google.com/maps/geo?q=台北市信義路五段七號101樓&output=csv&key=ABQIAAAAXDq__hWKi9eMCwnn7LrMCxT2yXp_ZAY8_ufC3CFXhHIE1NvwkxSnSVp_Xlsd4Ph5iyMua7PE5E0x_A";
URL iurl = new URL(url);
HttpURLConnection uc = (HttpURLConnection)iurl.openConnection();
uc.connect();
Object content = uc.getContent();
// 讀取結果
PlainTextInputStream sr = (PlainTextInputStream)content;
byte[] buf = new byte[2000];
// 解析 200,8,25.033408,121.564099 (HTTP status code, accuracy, latitude, longitude)
sr.read(buf);
String[] tmpArray = new String(buf, "UTF-8").split(",");
String latitude = tmpArray[2];
String longitude = tmpArray[3];
}
}
The problem is that the content i got a 400 code in result
i put the url in the browser, it return a 200 instead.
Is there a way to do that in a none browser matter?

have u tried Google Geo Kit
http://gglgeo.codeplex.com/? it is also in Java.

Related

Response code 400 is returned when specifying a specific scope on GoogleTV

Question
When I specify a specific scope, a response code of 400 is returned and I am unable to go to the authentication screen.
【400 error scope】
https://www.googleapis.com/auth/fitness.heart_rate.read
https://www.googleapis.com/auth/fitness.blood_pressure.read
https://www.googleapis.com/auth/fitness.body_temperature.read
【200 OK scope】
https://www.googleapis.com/auth/fitness.body.read
https://www.googleapis.com/auth/fitness.activity.read
If you know why the response code is different between 200 and 400 even though it is the same FitnessApi, please let me know.
Also, the scope for profile and email is returned at 200 normally.
Notes
Google Cloud Platform Settings
We have enabled the FitnessAPI.
For authentication information, client ID and client secret are generated using "Client ID for TVs and devices with limited input functions".
The Fitness scope described above is set in the OAuth consent screen settings of the Google Cloud Platform.
Relevant source
private static final String OAUTH_CODE_URL = "https://oauth2.googleapis.com/device/code";
private static final String OAUTH_TOKEN_URL = "https://oauth2.googleapis.com/token";
private static final String SCOPE_FITNESS_BODY = "https://www.googleapis.com/auth/fitness.body.read";
private static final String SCOPE_FITNESS_ACTIVITY = "https://www.googleapis.com/auth/fitness.activity.read";
private static final String SCOPE_FITNESS_HEART_RATE = "https://www.googleapis.com/auth/fitness.heart_rate.read";
private static final String SCOPE_FITNESS_BLOOD_PRESSURE = "https://www.googleapis.com/auth/fitness.blood_pressure.read";
private static final String SCOPE_FITNESS_BODY_TEMPERATURE = "https://www.googleapis.com/auth/fitness.body_temperature.read";
private static final String SCOPE_EMAIL = "email";
private static final String SCOPE_PROFILE = "profile";
:
public Object[] postAccessToken() {
String postBody = "client_id=" + OAUTH_CLIENT_ID +
"&scope=" + SCOPE_EMAIL +
"%20" + SCOPE_FITNESS_BODY_TEMPERATURE +
"%20" + SCOPE_FITNESS_ACTIVITY +
"%20" + SCOPE_FITNESS_BODY +
"%20" + SCOPE_FITNESS_HEART_RATE +
"%20" + SCOPE_FITNESS_BLOOD_PRESSURE +
"%20" + SCOPE_PROFILE;
return postAPI(OAUTH_CODE_URL, postBody);
}
:
public Object[] postAPI(String sendUrl, String sendPostData) {
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
OutputStream outputStream = null;
String result = "";
String str = "";
int statusCode = 0;
try {
URL url = new URL(sendUrl);
urlConnection = (HttpURLConnection) url.openConnection();
String postData = sendPostData;
urlConnection.setConnectTimeout(5000);
urlConnection.setReadTimeout(5000);
urlConnection.addRequestProperty("User-Agent", "Android");
urlConnection.addRequestProperty("Accept-Language", Locale.getDefault().toString());
urlConnection.setRequestMethod("POST");
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
urlConnection.connect();
outputStream = urlConnection.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, "utf-8"));
bufferedWriter.write(postData);
bufferedWriter.flush();
bufferedWriter.close();
// Get the response code
statusCode = urlConnection.getResponseCode();
OAuth 2.0 flow for TV and limited-input device applications have limited access scopes. However, these scopes are supported for other authentication flows, such as for mobile/desktop apps, and web apps.
The OAuth 2.0 flow for TV is supported only for the following scopes:
email
openid
profile

Unit Testing of Remote API calls, How it works with JSON Objects

In my web api, I have a method that call a service that return a deserialized JSON object. I can't find a way for unit testing that is working for me.
the following is the code from the controller:
[RequireHttps]
[Route("api/GetItem/{id}")]
public class GetItemController : ControllerBase
{
private static HttpClient client = new HttpClient();
private Item item = new Item();
[RequireHttps]
[Route("api/GetItem/{id}")]
public Item GetItem(string name, string password)
{
string url = "https://localhost:5001/";
string uri = url + "api/item/" + name+ "/" + password "/" ;
client.DefaultRequestHeaders.Accept.Add(new
MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage Res = client.GetAsync(uri).Result;
if (Res.IsSuccessStatusCode)
{
var MemResponse = Res.Content.ReadAsStringAsync().Result;
member = JsonConvert.DeserializeObject<Item>
(MemResponse);
}
return Ok(item);
}
}
The unit test I wrote suppose to check the wrong user name and password, but when running the test it just gray out and never runs
[TestMethod]
public void GetItemWithWrongPassword()
{
var username = "Hellow";
var pass = "There";
var controller = new GetItemController();
var response = controller.GetItem(username, pass);
var s = response.ToString();
Assert.AreEqual(s, "System.Web.Http.Results.NotFoundResult");
}
what I'm doing wrong?
Later on I want to test if the connection to the remote API.
Creating an instance of GetItemController and calling its methods is not a good idea, because the whole message pipeline is skipped in the process.
I see two options here:
Put the code (including the HttpClient) that is contained in GetItem into another class and call the method on an instance of that class, e.g.:
public class ItemClient
{
private static HttpClient client = new HttpClient();
public Item GetItem(string name, string password)
{
Item item = null;
string url = "https://localhost:5001/";
string uri = url + "api/item/" + name + "/" + password;
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage Res = client.GetAsync(uri).Result;
if (Res.IsSuccessStatusCode)
{
var MemResponse = Res.Content.ReadAsStringAsync().Result;
item = JsonConvert.DeserializeObject<Item>(MemResponse);
}
return item;
}
}
Controller method:
[RequireHttps]
[Route("api/GetItem/{name}/{password}")]
public Item GetItem(string name, string password)
{
ItemClient client = new ItemClient();
var item = client.GetItem(name, password);
return Ok(item);
}
Test method:
[TestMethod]
public void GetItemWithWrongPassword()
{
var username = "Hellow";
var password = "There";
ItemClient client = new ItemClient();
var item = client.GetItem(username, password);
Assert.IsNull(item);
}
Call the controller method using a HttpClient in the test method:
[TestMethod]
public void GetItemWithWrongPassword()
{
var username = "Hellow";
var password = "There";
string url = "https://localhost/"; // Host of your Web API
string uri = url + "api/GetItemController/GetItem/" + username + "/" + password;
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage Res = client.GetAsync(uri).Result;
var s = Res.ToString();
Assert.AreEqual(s, "System.Web.Http.Results.NotFoundResult");
}
I personally prefer option 1 due to two benefits:
Debugging the test is easier. Debugging a call by HttpClient (option 2)
usually means that you have to start a second instance of Visual
Studio and set a breakpoint there.
The code can be used in other projects that are not Web API services. The endpoints become simple wrappers around the actual business logic.

Starting Jenkins parameterized build with Jersey REST and JSON parameters

I have to start Jenkins parameterized build programmatically using Jersey REST API and the values for the parameters must be provided as a JSON object. Any hint or example is welcome.
So, seems like you have not tried it yourself. I can give you a fast 5 minute solution, that should be reworked to be clear and not so ugly, but it works :)
import java.util.ArrayList;
import java.util.List;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
public class JenkinsJob {
public static void main(String[] args) {
runParamJob("http://jenkins.host/", "SOME_JOB", "{\"object\":\"test\"}");
}
public static String runParamJob(String url, String jobName, String paramsJSON) {
String USERNAME = "user";
String PASSWORD = "pass";
Client client = Client.create();
client.addFilter(new com.sun.jersey.api.client.filter.HTTPBasicAuthFilter(USERNAME, PASSWORD));
WebResource webResource = client.resource(url + jobName + "/buildWithParameters?PARAMETER=" + paramsJSON);
ClientResponse response = webResource.type("application/json").get(ClientResponse.class, paramsJSON);
String jsonResponse = response.getEntity(String.class);
client.destroy();
System.out.println("Server response:" + jsonResponse);
return jsonResponse;
}
}
In order to use rest API for parameterized build you should use POST and not get according to Jenkins wiki. Here is an example. Make sure that the json you send is as instructed at the documentation.
take this json for example:
{"parameter": [{"name":"id", "value":"123"}, {"name":"verbosity", "value":"high"}]}
You have two parameters with name and value for each. If I will use what was written at the former answer by #stanjer the json should look like that:
{"parameter": [{"name":"object", "value":"test"}]}
In addition there is a good discussion about it here
I would not recommend to use USER:PASSWORD but use token that could be configured in Jenkins job UI. Here is a class that implements builder pattern for with/without parameters.
import java.util.Map;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.core.util.MultivaluedMapImpl;
public class JenkinsTrigger {
private String host;
private String jenkinsToken;
private String jobParams;
private MultivaluedMap<String,String> queryParams = new MultivaluedMapImpl();
private Client client = Client.create();
private WebResource webResource;
private JenkinsTrigger(JenkinsTriggerBuilder jenkinsTriggerBuilder){
this.host = jenkinsTriggerBuilder.host;
this.jenkinsToken = jenkinsTriggerBuilder.jenkinsToken;
this.jobParams = getJobParams(jenkinsTriggerBuilder.jobParams);
webResource = client.resource(this.host);
queryParams.add("token", jenkinsToken);
}
public void trigger(){
ClientResponse response = webResource.path(this.host).queryParams(queryParams)
.type(MediaType.APPLICATION_FORM_URLENCODED_TYPE)
.header("Content-type", "application/x-www-form-urlencoded")
.post(ClientResponse.class, jobParams);
if (response.getStatus() != 201) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.toString());
} else {
System.out.println("Job Trigger: " + host);
}
}
private String getJobParams(Map<String,String> jobParams){
StringBuilder sb = new StringBuilder();
sb.append("json={\"parameter\":[");
jobParams.keySet().forEach(param -> {
sb.append("{\"name\":\""+param+"\",");
sb.append("\"value\":\""+ jobParams.get(param) + "\"},");
});
sb.setLength(sb.length() - 1);
sb.append("]}");
System.out.println("Job Parameters:" + sb.toString());
return sb.toString();
}
public static class JenkinsTriggerBuilder {
private String host;
private String jenkinsToken;
private Map<String,String> jobParams = null;
public JenkinsTriggerBuilder(String host, String jenkinsToken){
this.host = host;
this.jenkinsToken = jenkinsToken;
}
public JenkinsTriggerBuilder jobParams(Map<String,String> jobParams){
this.jobParams = jobParams;
return this;
}
public JenkinsTrigger build(){
return new JenkinsTrigger(this);
}
}
}
And here is usage sample:
Map<String, String> params = new HashMap<>();
params.put("ENV", "DEV103");
JenkinsTrigger trigger = new JenkinsTriggerBuilder("https://JENKINS_HOST/job/JOB_NAME/buildWithParameters","JOB_TOKEN").jobParams(params).build();
trigger.trigger();
best of luck

Create empty file using Document List API 3.0

I am developing a feature which need to create a new empty file(not document) to Google drive, now I am using document list API 3.0 and I am referring to the document: https://developers.google.com/google-apps/documents-list/#uploading_a_new_document_or_file_with_both_metadata_and_content.
I will upload a zero byte file to the Google drive to generate the empty file.
Now I have a problem during request step 1 and request step 2. After the first Post[resumable-create-media link] request I successfully got the upload location. Then when I request put method to the location, I got a 404 not found error. All of the requests have "GData-Version: 3.0" and "Authorization: accessToken" headers.
I searched a lot from the forum and figured out how to create empty document but could not figure out how to create empty file. Here is my code, could anybody help to see which part is wrong? Thanks in advance.
private final static String PARAM_CONTENT_TYPE = "Content-Type";
private final static String PARAM_UPLOAD_LENGTH = "X-Upload-Content-Length";
private final static String PARAM_UPLOAD_TYPE = "X-Upload-Content-Type";
private final static String CONTENT_TYPE_XML = "application/atom+xml";
private final static String URI_RESUMABLE_RESOURCE = "https://docs.google.com/feeds/upload/create-session/default/private/full";
private final static String ENTITY_NEW_FILE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><entry xmlns=\"http://www.w3.org/2005/Atom\" "
+ "xmlns:docs=\"http://schemas.google.com/docs/2007\"><title>{0}</title></entry>";
#Override
public boolean createNewFile() throws IOException {
String uri = null;
if (ROOT.equals(parentResourceId))
uri = URI_RESUMABLE_RESOURCE;
else
uri = URI_RESUMABLE_RESOURCE + "/%3A" + parentResourceId + "/contents";
try {
StringEntity entity = new StringEntity(MessageFormat.format(ENTITY_NEW_FILE, getName()), Constants.ENCODING);
Map<String, String> headers = new HashMap<String, String>();
headers.put(PARAM_CONTENT_TYPE, CONTENT_TYPE_XML);
headers.put(PARAM_UPLOAD_LENGTH, "0");
headers.put(PARAM_UPLOAD_TYPE, "text/plain");
Map<String, String> params = new HashMap<String, String>();
params.put("convert", "false");
HttpResponse response = helper.execMethodAsResponse(uri, new PostMethod(entity), headers, params);
String location = null;
if ((location = response.getFirstHeader("Location").getValue()) != null) {
headers = new HashMap<String, String>();
headers.put(PARAM_CONTENT_TYPE, "text/plain");
headers.put("Content-Range", "bytes 0-0/0");
//FIXME: Problem occurs here, this put invocation will return 404 not found error.
JsonObject obj = helper.execMethodAsJson(location, new PutMethod(new ByteArrayEntity(new byte[0])), headers, null);
if (obj != null) {
decorateFile(this, obj.get("entry").getAsJsonObject());
return true;
}
}
} catch (UnsupportedEncodingException e) {
}
return false;
}
The easiest way to create an empty file on Google Drive is to use the Google Drive API v2 and send a service.files.insert(File content) request.
You can use the Java sample from the Reference Guide and edit it to not include a MediaContent: https://developers.google.com/drive/v2/reference/files/insert
I have figured out the problem, according to this link: Google Documents List API file upload 400 response
The second put request does not need any additional headers such as "GData-Version: 3.0" and "Authorization: Bearer ****", etc. The only thing need to do is new a put request with the location URI, then it will return response with 201 status code.
Thanks all.

Google Maps API web service not providing accurate latitude longitude

I have used the code below to get latitude and longitude in C#.Net. But in some cases it provides the wrong latitude/longitude. For example, if I search "Braås skola Växjö Sweden" it provides [56.879004,14.805852] which is Växjö's latitude/longitude not what we searched! So how do we resolve this problem to get the exact latitude/longitude. This problem happens in many cases like "Braås förskola 44:an VÄXJÖ", "Björkens förskola VÄXJÖ".
private const String _googleUri = "http://maps.google.com/maps/geo?q=";
private const String _googleKey = "yourkey";
private const String _outputType = "csv";
private static Uri GetGeocodeUri(String address) {
address = HttpUtility.UrlEncode(address);
return new Uri(String.Format("{0}{1}&output={2}&key={3}", _googleUri,
address, _outputType, _googleKey));
}
public static Coordinate GetCoordinates(String address) {
WebClient client = new WebClient();
Uri uri = GetGeocodeUri(address);
String[] geocodeInfo = client.DownloadString(uri).Split(',');
return new Coordinate(Convert.ToDecimal(geocodeInfo[2]), Convert.ToDecimal(geocodeInfo[3]));
}
Please help me get a better solution.
Request the places-service instead of geocoding.