I'm creating some big files (DB exports) with Java and I need to put them somewhere on our SharePoint server. Right now, I'm doing this with IE but I'd like to automate this step, too.
I searched the web and I found some hints to use SOAP but I don't really see to the ground of all this, yet. Can someone provide me with some sample code or a recipe what I need to do?
Please note: the SharePoint server asks for NT domain authentication. I can't even login with Firefox :(
EDIT
How do I convert the scary URL in IE into a WebDAV path?
Is there a WebDAV "explorer" which I can use before I ruin the production system with my code? I tried "DAV Explorer 0.91" from http://www.davexplorer.org/ but that can't connect (probably because of NT domain auth).
In addition to Sacha's suggestions, you can use the SharePoint SOAP web services. Each SharePoint site exposes a bunch of web services via the path http://<Site>/_vti_bin/.
In your case, you probably want the Lists web service (http://<Site>/_vti_bin/Lists.asmx). You can grab the WSDL from http://<Site>/_vti_bin/Lists.asmx?WSDL. The WSS 3.0 SDK has details on how to use the web service (you'll probably want to use the UpdateListItems and AddAttachment methods).
All that said, Sacha's first option (mapping a document library to a drive) is probably the easiest way assuming you can get around the NTLM issues.
If you're using Windows you can simply navigate to a UNC path for a document library. For example, if the browser URL for your document library is:
http://<Site>/Foo/BarDocs/Forms/AllItems.aspx
you can simply type the corresponding UNC path in the Windows Explorer address bar:
\\<Site>\Foo\BarDocs
and then drag and drop files to this location. If you'd like you can map this location to a drive letter using Windows Explorer or the SUBST.EXE command-line utility.
Okay ... after several hours of work and biting myself through the "documentation" MicroSoft provides and all the hints randomly spread over the 'net, I've managed to write some sample code to browse the content of a SharePoint server: Navigating SharePoint Folders With Axis2.
Next stop: Uploading something.
An other solution is to use HTTP PUT method to send a file directly to the Sharepoint.
For that you can use Apache HTTP Client:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.2.3</version>
</dependency>
And to permit NTLMv2 authentication you need JCIF library.
<dependency>
<groupId>jcifs</groupId>
<artifactId>jcifs</artifactId>
<version>1.3.17</version>
</dependency>
First we need to write a wrapper to permit Apache HTTP Client to use JCIF for NTLMv2 support :
public final class JCIFSEngine implements NTLMEngine {
private static final int TYPE_1_FLAGS =
NtlmFlags.NTLMSSP_NEGOTIATE_56
| NtlmFlags.NTLMSSP_NEGOTIATE_128
| NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2
| NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN
| NtlmFlags.NTLMSSP_REQUEST_TARGET;
#Override
public String generateType1Msg(final String domain, final String workstation)
throws NTLMEngineException {
final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation);
return Base64.encode(type1Message.toByteArray());
}
#Override
public String generateType3Msg(final String username, final String password,
final String domain, final String workstation, final String challenge)
throws NTLMEngineException {
Type2Message type2Message;
try {
type2Message = new Type2Message(Base64.decode(challenge));
} catch (final IOException exception) {
throw new NTLMEngineException("Invalid NTLM type 2 message", exception);
}
final int type2Flags = type2Message.getFlags();
final int type3Flags = type2Flags
& (0xffffffff ^ (NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER));
final Type3Message type3Message = new Type3Message(type2Message, password, domain,
username, workstation, type3Flags);
return Base64.encode(type3Message.toByteArray());
}
}
Reference
The main code to execute HTTP PUT with authentication:
try {
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
DefaultHttpClient httpclient = new DefaultHttpClient(params);
//Register JCIF NTLMv2 to manage ntlm auth.
httpclient.getAuthSchemes().register("ntlm", new AuthSchemeFactory() {
#Override
public AuthScheme newInstance(HttpParams hp) {
return new NTLMScheme(new JCIFSEngine());
}
});
//Provide login/password
httpclient.getCredentialsProvider().setCredentials(
AuthScope.ANY,
new NTCredentials([LOGIN], [PASSWORD], "", [DOMAIN]));
//Create HTTP PUT Request
HttpPut request = new HttpPut("http://[server]/[site]/[folder]/[fileName]");
request.setEntity(new FileEntity([File]));
return httpclient.execute(request);
} catch (IOException ex) {
//...
}
I can think of different options:
Mapping the Document library to a file drive and just save the file like any other file in the file system.
Using HTTP WebDAV protocol.
...and for the NTLM authentication part:
http://www.luigidragone.com/networking/ntlm.html
I think my approach might help you.
Initially i have created sharepoint account and followed the procedure in this link (http://www.ktskumar.com/2017/01/access-sharepoint-online-using-postman/) to get needed credentials for REST API's. once i got the credentials all i needed was the following dependency and code:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5</version>
</dependency>
Since i used OAUTH2 authentication, the code to get access token helps for other CRUD operations.
/* OAuth2 authentication to get access token */
public String getSharePointAccessToken() throws ClientProtocolException, IOException
{
/* Initializing variables */
String grant_type = RcConstants.GRANT_TYPE;
String client_id = RcConstants.CLIENT_ID;
String client_secret = RcConstants.CLIENT_SECRET;
String resource = RcConstants.RESOURCE;
String url = RcConstants.OAUTH_URL + RcConstants.URL_PARAMETER + "/tokens/OAuth/2";
/*
* NOTE: RcConstants.OAUTH_URL =
* https://accounts.accesscontrol.windows.net/ RcConstants.URL_PARAMETER
* = Bearer Realm from
* (http://www.ktskumar.com/2017/01/access-sharepoint-online-using-
* postman/) Figure 6.
*/
/* Building URL */
HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost(url);
post.setHeader("Content-Type", "application/x-www-form-urlencoded");
/* Adding URL Parameters */
List<NameValuePair> urlParameters = new ArrayList<NameValuePair>();
urlParameters.add(new BasicNameValuePair("grant_type", grant_type));
urlParameters.add(new BasicNameValuePair("client_id", client_id));
urlParameters.add(new BasicNameValuePair("client_secret", client_secret));
urlParameters.add(new BasicNameValuePair("resource", resource));
post.setEntity(new UrlEncodedFormEntity(urlParameters));
/* Executing the post request */
HttpResponse response = client.execute(post);
logger.debug("Response Code : " + response.getStatusLine().getStatusCode());
String json_string = EntityUtils.toString(response.getEntity());
JSONObject temp1 = new JSONObject(json_string);
if (temp1 != null)
{
/* Returning access token */
return temp1.get("access_token").toString();
}
return RcConstants.OAUTH_FAIL_MESSAGE;
}
Once we get access token we can upload using following method:
public String putRecordInSharePoint(File file) throws ClientProtocolException, IOException
{
/* Token variable declaration */
String token = getSharePointAccessToken();
/* Null or fail check */
if (!token.equalsIgnoreCase(RcConstants.OAUTH_FAIL_MESSAGE))
{
/* Upload path and file name declaration */
String Url_parameter = "Add(url='" + file.getName() + "',overwrite=true)";
String url = RcConstants.UPLOAD_FOLDER_URL + Url_parameter;
/*
* NOTE: RcConstants.UPLOAD_FOLDER_URL =
* https://<your_domain>.sharepoint.com/_api/web/
* GetFolderByServerRelativeUrl('/Shared%20Documents/<FolderName>')/
* Files/
*/
/* Building URL */
HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost(url);
post.setHeader("Authorization", "Bearer " + token);
post.setHeader("accept", "application/json;odata=verbose");
/* Declaring File Entity */
post.setEntity(new FileEntity(file));
/* Executing the post request */
HttpResponse response = client.execute(post);
logger.debug("Response Code : " + response.getStatusLine().getStatusCode());
if (response.getStatusLine().getStatusCode() == HttpStatus.OK.value()|| response.getStatusLine().getStatusCode() == HttpStatus.ACCEPTED.value())
{
/* Returning Success Message */
return RcConstants.UPLOAD_SUCCESS_MESSAGE;
}
else
{
/* Returning Failure Message */
return RcConstants.UPLOAD_FAIL_MESSAGE;
}
}
return token;
}
I managed to up and download files to sharepoint with this code, using the integrated Windows identification, maybe it helps.
public class HttpClient {
HttpClient() { }
public static void download(final String source, final File resultingFile) {
CloseableHttpClient client = WinHttpClients.createSystem();
HttpGet httpRequest = new HttpGet(source);
CloseableHttpResponse httpResponse = null;
try {
httpResponse = client.execute(httpRequest);
HttpEntity entity = httpResponse.getEntity();
if(httpResponse.getStatusLine() != null && httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
LOGGER.warn(httpResponse.getStatusLine());
}else {
LOGGER.debug(httpResponse.getStatusLine());
FileUtils.touch(resultingFile);
InputStream is = entity.getContent();
File outFile = new File(resultingFile.getAbsolutePath());
FileOutputStream fos = new FileOutputStream(outFile);
int inByte;
while ((inByte = is.read()) != -1) {
fos.write(inByte);
}
is.close();
fos.close();
client.close();
}
} catch (ClientProtocolException e) {
LOGGER.warn(e);
} catch (UnsupportedOperationException e) {
LOGGER.warn(e);
} catch (IOException e) {
LOGGER.warn(e);
}
}
public static void upload(final File source, final String destination) {
CloseableHttpClient httpclient = WinHttpClients.createSystem();
HttpPut httpRequest = new HttpPut(destination);
httpRequest.setEntity(new FileEntity(new File(source.getPath())));
CloseableHttpResponse httpResponse = null;
try {
httpResponse = httpclient.execute(httpRequest);
EntityUtils.consume(httpResponse.getEntity());
if (httpResponse.getStatusLine() != null && httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED) {
LOGGER.debug(httpResponse.getStatusLine());
LOGGER.info("Upload of " + source.getName() + " via HTTP-Client succeeded.");
} else if (httpResponse.getStatusLine() != null && httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
LOGGER.debug(httpResponse.getStatusLine());
}else {
LOGGER.warn("Uploading " + source.getName() + " failed.");
LOGGER.warn(httpResponse.getStatusLine().getStatusCode() + ": " + httpResponse.getStatusLine().getReasonPhrase());
}
} catch (IOException e) {
LOGGER.warn(e);
LOGGER.warn(e.getMessage());
}
return;
}
}
WinHttpClients:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient-win</artifactId>
<version>4.4</version>
</dependency>
Path:
org.apache.http.impl.client.WinHttpClients
Description:
Factory methods for CloseableHttpClient instances configured to use integrated Windows authentication by default.
Related
I've seen couple of qts on the same topic. But I didn't find any clue of this error.
I am working on a POC and following the link below.
http://spring.io/guides/gs/uploading-files/
As mentioned in the above tutorial, in standalone mode[spring embeded Tomcat] it is working absolutely fine.
But I want to deploy it as webapplication. So, I have created a separate SpringMVC project and added the following controller.
Controller file
#Controller
public class FileUploadController {
#RequestMapping(value="/upload", method=RequestMethod.GET)
public #ResponseBody String provideUploadInfo() {
return "You can upload a file by posting to this same URL.";
}
#RequestMapping(value="/upload", method=RequestMethod.POST)
public #ResponseBody String handleFileUpload(#RequestParam("name") String name,
#RequestParam("file") MultipartFile file){
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
BufferedOutputStream stream =
new BufferedOutputStream(new FileOutputStream(new File(name + "-uploaded")));
stream.write(bytes);
stream.close();
return "You successfully uploaded " + name + " into " + name + "-uploaded !";
} catch (Exception e) {
return "You failed to upload " + name + " => " + e.getMessage();
}
} else {
return "You failed to upload " + name + " because the file was empty.";
}
}
}
I've written the following client ( As I don't want to use RestTemplate here).
Service Client
private static final String URL_GET = "http://localhost:8080/SpringMVC/upload";
static String URL = "http://localhost:8080/SpringMVC/upload";
public static void main(String[] args) throws Exception {
PropertyConfigurator.configure("C:/DevEnvProject/eclipse/workspace_exp/OCR/log4j.properties");
testGet();
testPOST();
}
private static void testGet() throws ClientProtocolException, IOException {
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpGet = new HttpGet(URL_GET);
HttpResponse response = httpClient.execute(httpGet, localContext);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
String sResponse = reader.readLine();
}
static void testPOST() {
try {
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpPost httpPost = new HttpPost(URL);
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("name", new StringBody("testIcon.png"));
entity.addPart("file", new FileBody(new File("C:/testIcon.png")));
httpPost.setEntity(entity);
HttpResponse response = httpClient.execute(httpPost, localContext);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
String sResponse = reader.readLine();
} catch (Exception e) {
e.printStackTrace();
}
}
I couldn't make a successful call to the POST endpoint. Everytime, I'm getting the following exception.
400 Bad Request - The request sent by the client was syntactically incorrect
'GET' call is working fine. I compared the the log of the 'POST' request with the same 'POST' request which I got while testing with standalone approach as mentioned in the spring tutorial. Didn't find any diff in the request part.
I know that I'm quite verbose in this post. I wanted to give as much context info as possible. Please help.
Thanks
There are 2 things you need to do:
First, add the Apache Commons FileUpload library to your class path. If you use maven, you can get the dependency here. If you don't, you can still download the jar and add it manually.
Second, you have to declare a MultipartResolver bean in your context with name multipartResolver. With Apache Commonds FileUpload, you can use CommonsMultipartResolver. For example, with Java config, that would be
#Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
// set any fields
return commonsMultipartResolver;
}
With XML config,
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- set any properties -->
</bean>
This is further documented in the Spring official documentation.
We have some videos (mp4) that are stored behind our firewall. I have a Java proxy that is used to serve up other documents like PDFs, DOCs, etc. to external sites via a RESTful web service. This same web service works for videos in PC browsers but on the iPad I just get a black screen with the play button blocked. If I browse to the direct location of the video it plays fine. That leads me to believe the video is fine, but I am missing something in my web service code that serves it back up. Any ideas out there? Has anyone else conquered this on the iPad?
#GET
#Path("/open/{objectId}/{ticket}/{objectName}/")
public Response openDocument(#PathParam("objectId") String objectId, #PathParam("ticket") String ticket, #PathParam("objectName") String objectName) throws Exception {
return download(objectId, ticket, objectName, false);
}
private Response download(String objectId, String ticket, String objectName, boolean attachment) throws Exception {
String url = "";
if (objectName.endsWith(".mp4")) {
url = "http://videosite.com/videos/" + objectName;
}
else {
url = "http://documentsite.com/" + objectName;
}
DefaultHttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(url);
try {
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
StatusLine status = response.getStatusLine();
if (status.getStatusCode() == 200 || status.getStatusCode() == 206) {
ResponseBuilder rb = Response.ok(entity.getContent());
rb.header("Connection", "Keep-Alive");
rb.header("Content-Length", entity.getContentLength());
rb.header("Content-Type", entity.getContentType().getValue());
rb.header("Keep-Alive", "timeout=5, max=99");
if (attachment) rb.header("Content-Disposition", "attachment; filename=\"" + objectName.replaceAll("\\+", " ") + "\"");
else rb.header("Content-Disposition", "filename=\"" + objectName.replaceAll("\\+", " ") + "\"");
return rb.build();
}
else return Response.noContent().build();
}
catch (Exception e) {
e.printStackTrace();
return Response.noContent().build();
}
}
After working with iOS and dealing with auth challenges without much of a learning curve, I've found that Windows Authentication is much more complicated of a process in Java/Android.
I tried multiple different approaches, so without getting too much into those, I will get to the one that worked for the most part. I'm now using the class created for NTLM and ksoap called NtlmTransport
I'm now successfully authenticating in the following way:
NtlmTransport httpTransport = new NtlmTransport();
httpTransport.setCredentials(serverURL, Login.username, Login.password, deviceIp, "DOMAINNAME");
httpTransport.call(SOAP_ACTION, envelope);
If you take a look at the NtlmTransport class, you'll see that it's returning the following headers from the setupNtlm():
status Line HTTP/1.1 200 OK
Setup Cache-Control:private, max-age=0
Setup Content-Type:text/html; charset=utf-8
Setup Server:Microsoft-IIS/8.0
Setup X-AspNet-Version:4.0.30319
Setup Persistent-Auth:true
Setup X-Powered-By:ASP.NET
Setup Date:Tue, 17 Sep 2013 20:57:45 GMT
Setup Content-Length:11549
The "Persistent-Auth:true is the main one I'm concerned about at this time. I'm getting the SoapObjects just fine and can get the data I need from that one connection, but as soon as I try to access the web service again, which is presumably able to be hit after the successful authentication, I can't access a different method using HttpTransportSE:
private void setSomething() {
xml = null;
final String SOAP_ACTION = "http://this.ismy.org/AWebServiceMethod";
final String METHOD_NAME = "AWebServiceMethod";
final String URL = protocol + "://" + host + ":" + port + "/WebService.asmx";
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
envelope.implicitTypes = true;
envelope.setAddAdornments(false);
try
{
HttpTransportSE transport = new HttpTransportSE(URL);
transport.debug = true;
transport.call(SOAP_ACTION, envelope);
xml = transport.responseDump.toString();
Log.d(TAG, xml);
}
catch(SocketException ex)
{
Log.e("SocketException : " , "Error on setSomething() " + ex.getMessage());
}
catch (Exception e)
{
Log.e("Exception : " , "Error on setSomething() " + e.getMessage());
}
}
This all works just fine as the background task of an AsyncTask, which then passes the "xml" to an XMLPullParser method.
The main question here is why am I getting a:
Error on setSomething() No authentication challenges found
??
After IIS successfully validates the user with a 200, why is it asking me to authenticate again? How can I persist that first authenticated challenge to hit whatever method I want inside WebService.asmx? What are the headers that need to be added/changed to create a session if necessary? What am I missing that makes this whole NTLM process work and persist for more than the WS method that needs to pass the authentication challenges?
EDIT : Adding the Library code
Here's the link to the JCIFS from Apache
public static final class JCIFSEngine implements NTLMEngine {
private static final int TYPE_1_FLAGS =
NtlmFlags.NTLMSSP_NEGOTIATE_56 |
NtlmFlags.NTLMSSP_NEGOTIATE_128 |
NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2 |
NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
NtlmFlags.NTLMSSP_REQUEST_TARGET;
public String generateType1Msg(final String domain, final String workstation)
throws NTLMEngineException {
final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation);
return jcifs.util.Base64.encode(type1Message.toByteArray());
}
public String generateType3Msg(final String username, final String password,
final String domain, final String workstation, final String challenge)
throws NTLMEngineException {
Type2Message type2Message;
try {
type2Message = new Type2Message(jcifs.util.Base64.decode(challenge));
} catch (final IOException exception) {
throw new NTLMEngineException("Invalid NTLM type 2 message", exception);
}
final int type2Flags = type2Message.getFlags();
final int type3Flags = type2Flags
& (0xffffffff ^ (NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER));
final Type3Message type3Message = new Type3Message(type2Message, Login.password, "",
Login.username, deviceIp, type3Flags);
System.out.println("type3Message: " + type3Message.toByteArray());
return jcifs.util.Base64.encode(type3Message.toByteArray());
}
}
So is the "NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN" causing this problem? Is there another flag I'm supposed to set for the keep-alive? Also, I found a great resource for a list of NTLM flags and more: http://fossies.org/dox/jcifs-1.3.17/interfacejcifs_1_1ntlmssp_1_1NtlmFlags.html
I was also struggling about windows authentication from Android.
I found android-ntlm-master on https://github.com/masconsult/android-ntlm. Add this class as library in your project.
Change is in NtlmTransport.java class.I made change in call method of NtlmTransport class =>
public List call(String soapAction, SoapEnvelope envelope,
List headers, File outputFile)
throws IOException, XmlPullParserException {
HttpResponse resp = null;
try {
//setupNtlm(urlString, user, password);
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getAuthSchemes().register("ntlm", new NTLMSchemeFactory());
httpclient.getCredentialsProvider().setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
new NTCredentials(user, password, "", "")
);
HttpPost httpget = new HttpPost(urlString);
httpget.addHeader("soapaction", soapAction);
httpget.addHeader("Content-Type", "text/xml; charset=utf-8");
byte[] requestData = null;
try {
requestData = createRequestData(envelope);
} catch (IOException iOException) {
}
ByteArrayEntity byteArrayEntity = new ByteArrayEntity(requestData);
httpget.setEntity(byteArrayEntity);
resp = httpclient.execute(httpget);
if(resp == null) {
System.out.println("Response is null");
}
HttpEntity respEntity = resp.getEntity();
InputStream is = respEntity.getContent();
if(is == null) {
System.out.println("InputStream is null");
}
parseResponse(envelope, is);
} catch (Exception ex) {
// ex.printStackTrace();
}
if (resp != null) {
return Arrays.asList(resp.getAllHeaders());
} else {
return null;
}
}
And below is the code how I make call:
SoapObject request = new SoapObject(NAMESPACE, PRODUCT_DETAILS_METHOD_NAME);
request.addProperty("ListingID", Integer.parseInt(Product_ID));
NtlmTransport httpTransport = new NtlmTransport();
httpTransport.setCredentials(URL, USERNAME, PASSWORD, "","");
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.implicitTypes = true;
envelope.setOutputSoapObject(request);
httpTransport.call(PRODUCT_DETAILS_SOAP_ACTION, envelope);
SoapObject response = (SoapObject) envelope.getResponse();
It worked for me.
More you can find here: https://suhas1989.wordpress.com/2015/01/28/ntlm-authentication-in-android/
I am trying to set up google cloud messaging for my app, and I am using Google App Engine for my server. I have my API key but I can't seem to make a connection to the google cloud messaging servers. Here is my code.
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("https://android.googleapis.com/gcm/send");
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("registration_id", regId));
nameValuePairs.add(new BasicNameValuePair("data.message", messageText));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
post.setHeader("Authorization", "key=*MY_API_KEY_HERE*");
post.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
Header[] s=post.getAllHeaders();
System.out.println("The header from the httpclient:");
for(int i=0; i < s.length; i++){
Header hd = s[i];
System.out.println("Header Name: "+hd.getName()
+" "+" Header Value: "+ hd.getValue());
}
HttpResponse response = client.execute(post);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
When I look at the log the headers are being setup right. However, I get an error that says
org.apache.http.impl.client.DefaultRequestDirector tryConnect: I/O exception (java.net.SocketException) caught when connecting to the target host: Permission denied: Attempt to access a blocked recipient without permission. (mapped-IPv4)
I've turned google cloud messaging on in the Google APIs Console and I've checked my API key a bunch of times. I have no clue why I'm getting rejected. Is there a jar I need in the war or something I have to put in the manifest?
Thanks for reading this!!
Mark
I had the same problem and I was using something similar to what you are using.
I had to enable billing on my GAE app ( which you probably have but I wasn't aware that I would have to)
Read https://developers.google.com/appengine/docs/java/sockets/ and https://developers.google.com/appengine/docs/java/urlfetch/
Therefore my code which looked like yours before now looks like following:
String json ="{}";
URL url = new URL("https://android.googleapis.com/gcm/send");
HTTPRequest request = new HTTPRequest(url, HTTPMethod.POST);
request.addHeader(new HTTPHeader("Content-Type","application/json"));
request.addHeader(new HTTPHeader("Authorization", "key=<>"));
request.setPayload(json.getBytes("UTF-8"));
HTTPResponse response = URLFetchServiceFactory.getURLFetchService().fetch(request);
I was also implementing GCM with GAE, and I had an error like this:
com.google.apphosting.api.ApiProxy$FeatureNotEnabledException: The Socket API will be enabled for this application once billing has been enabled in the admin console.
Nikunj answer helped me too. After implementing what he suggested, notifications are delivered to the device, without need for enabling billing for my GAE App.
Here is my implementation, just in case, may be useful for someone with same problem:
private void sendNotificationRequestToGcm(List<String> registrationIds) {
LOG.info("In sendNotificationRequestToGcm method!");
JSONObject json = new JSONObject();
JSONArray jasonArray = new JSONArray(registrationIds);
try {
json.put("registration_ids", jasonArray);
} catch (JSONException e2) {
LOG.severe("JSONException: " + e2.getMessage());
}
String jsonString = json.toString();
LOG.info("JSON payload: " + jsonString);
com.google.appengine.api.urlfetch.HTTPResponse response;
URL url;
HTTPRequest httpRequest;
try {
//GCM_URL = https://android.googleapis.com/gcm/send
url = new URL(GCM_URL);
httpRequest = new HTTPRequest(url, HTTPMethod.POST);
httpRequest.addHeader(new HTTPHeader("Content-Type","application/json"));
httpRequest.addHeader(new HTTPHeader("Authorization", "key=" + API_KEY));
httpRequest.setPayload(jsonString.getBytes("UTF-8"));
LOG.info("Sending POST request to: " + GCM_URL);
response = URLFetchServiceFactory.getURLFetchService().fetch(httpRequest);
LOG.info("Status: " + response.getResponseCode());
List<HTTPHeader> hdrs = response.getHeaders();
for(HTTPHeader header : hdrs) {
LOG.info("Header: " + header.getName());
LOG.info("Value: " + header.getValue());
}
} catch (UnsupportedEncodingException e1) {
LOG.severe("UnsupportedEncodingException" + e1.getMessage());
} catch (MalformedURLException e1) {
LOG.severe("MalformedURLException" + e1.getMessage());
} catch (IOException e) {
LOG.severe("URLFETCH IOException" + e.getMessage());
}
}
Hope this will help someone...
The easiest way is to use gcm-server.jar (which you can get from here).
Then the code you'll need to send a GCM message will look like this :
Sender sender = new Sender(apiKey);
Message message = new Message.Builder()
.addData("message", "this is the message")
.addData("other-parameter", "some value")
.build();
Result result = sender.send(message, registrationId, numOfRetries);
Here's the gradle dependency:
compile 'com.google.gcm:gcm-server:1.0.0'
and mvnrepository url
source
I having an issue from my HTTP Post.
The code I'm using are working (have tested to post data to a guestbook form and it worked).
Now what I want. I have created two EditText forms, that holds values. I have a submit button there I post this data (like the test I wrote about before), but now I want to post it into a login.php page (that in a normal browser redirects me to the member.php page).
Although I know the forms are correctly filled in and it successfully posted on the "test" site, I wanna get the response from login.php and check if the user is successfully logged in or if it failed, if succeeded -> redirect me to member.php page.
All I know is this:
HttpResponse response = httpclient.execute(httppost);
that executes the command. But how should I achieve the login check? Any further use of the response variable?
Well... your approach is not good at all. If you are going to allow user authenticate through your app, why do you want to redirect the user to a member.php page? why don't you just put the login form in a login.php file on the server and make the user browse through your site?
As user, if an app allows me to authenticate using EditTexts inside UI, I would expect to access all the content through the app instead of being redirected to a web interface.
Anyway, if you decide to continue doing it that way keep in mind that you would have to parse and process cookies manually, and inject them into the WebView (Google about the CookieManager class). That's the way how the user will really be logged-in in your web app.
Can you provide a small example of how to set it up? The stream I will get, is that a special server response for example, a successfully login?
Here you have:
public String getPostRequest(String url, String user, String pass) {
HttpClient postClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
HttpResponse response;
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("user", user));
nameValuePairs.add(new BasicNameValuePair("pass", pass));
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
response = postClient.execute(httpPost);
if(response.getStatusLine().getStatusCode() == 200) {
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
String result = convertStreamToString(instream);
instream.close();
return result; // here is a string of the result!!!
}
}
} catch (Exception e) {}
return null; // if it gets here, something wrong happens with the connection
}
private String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
How do you use it? Something like this:
String result = getPostRequest("http://yourpage.com/login.php", "the username", "his/her pass");
if( result.equals("OK") ){
// voila!
}
I'm here supposing that you have something like this in your PHP code:
<?php
// login logic here
if( $success ){
die("OK");
}
?>