How to upload file on GAE with GWT? - google-app-engine

I've been trying this for hours, so maybe a fresh set of eyes will help.
I'm trying to upload a file to the server using GWT (using UiBinder) on Google App Engine. Following all the examples I can find, things look like they should work, but the server's 'post' method is showing 0 items uploaded.
Here's the client code:
FormUploader.ui.xml:
<g:FormPanel action="/formImageUploader" ui:field="formPanel">
<g:VerticalPanel>
<g:FileUpload ui:field="uploader"></g:FileUpload>
<g:Button ui:field="submit">Submit</g:Button>
</g:VerticalPanel>
</g:FormPanel>
FormUploader.java:
#UiField
FormPanel formPanel;
#UiField
FileUpload uploader;
#UiField
Button submit;
public FormUploader() {
initWidget(uiBinder.createAndBindUi(this));
formPanel.setEncoding(FormPanel.ENCODING_MULTIPART);
formPanel.setMethod(FormPanel.METHOD_POST);
addSubmitHandlers();
}
private void addSubmitHandlers() {
formPanel.addSubmitCompleteHandler(new SubmitCompleteHandler() {
#Override
public void onSubmitComplete(SubmitCompleteEvent event) {
Core.log("Inside submitComplete");
Window.alert(event.getResults());
}
});
}
web.xml:
<servlet>
<servlet-name>formImageUploader</servlet-name>
<servlet-class>com.company.server.FormImageUploader</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>formImageUploader</servlet-name>
<url-pattern>/formImageUploader</url-pattern>
</servlet-mapping>
FormImageUploader.java:
public class FormImageUploader extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
log.info("Request.getContentLength(): " + request.getContentLength());
log.info("Content type: " + request.getContentType());
log.info("Parm names: ");
for (Object paramName : request.getParameterMap().keySet()) {
log.info("__Param name: " + paramName.toString());
}
log.info("Attribtue names: ");
Enumeration enu = request.getAttributeNames();
while (enu.hasMoreElements()) {
log.info("__Attribute name: " + enu.nextElement().toString());
}
log.info("Header names: ");
enu = request.getHeaderNames();
while (enu.hasMoreElements()) {
log.info("__Header name: " + enu.nextElement().toString());
}
resp.getWriter().println("Post Code has finished executing");
}
All this executes just fine, the client shows an alert box containing Post Code has finished executing, but I can't figure out how to get the content of the file I want to upload.
Here's the server side log:
Request.getContentLength(): 63
Content type: multipart/form-data; boundary=---------------------------194272772210834546661
Parm names:
Attribtue names:
__Attribute name: com.google.apphosting.runtime.jetty.APP_VERSION_REQUEST_ATTR
Can anyone help me see why I'm not seeing any files on the server after clicking "submit" on the client?
Thanks in advance
Edit:
Still can't figure out why I can't get the form data on the server. I'm following this example, and just trying to write the response out to the client, but the server is definitely not seeing any content from the client.
Server code:
try {
log.info("Inside try block");
ServletFileUpload upload = new ServletFileUpload();
log.info("created the servlet file upload");
res.setContentType("text/plain");
log.info("set the content type to text/plain");
FileItemIterator iterator = upload.getItemIterator(req);
log.info("Got the iterator for items");
while (iterator.hasNext()) {
log.info("__inside iterator.hasNext");
FileItemStream item = iterator.next();
log.info("__assigned the file item stream");
InputStream stream = item.openStream();
log.info("__opened said stream");
if (item.isFormField()) {
log.warning("Got a form field: " + item.getFieldName());
} else {
log.warning("Got an uploaded file: " + item.getFieldName() +
", name = " + item.getName());
int len;
byte[] buffer = new byte[8192];
while ((len = stream.read(buffer, 0, buffer.length)) != -1) {
res.getOutputStream().write(buffer, 0, len);
}
log.info("Done writing the input to the output stream");
}
}
} catch (Exception ex) {
log.severe("Exception; " + ex);
throw new ServletException(ex);
}
log.info("Done parseInput3");
Logs:
Inside parseInput3
Inside try block
created the servlet file upload
set the content type to text/plain
Got the iterator for items
Done parseInput3
Again, it's definitely not able to iterate over the file items on the server... any idea why?

Turns out, GAE has a completely different way of uploading files (Blobs):
http://code.google.com/appengine/docs/java/blobstore/overview.html#Uploading_a_Blob
You need to supply the form's on the client with a Blobstore Upload URL (which times out) from the server, retrieved using:
blobstoreService.createUploadUrl('urlToRedirectToAfterUploadComplete')
After setting that upload URL on the form's action, the form will be submitted and the blobstore service will redirect to the supplied URL, which can then access the BlobKey of the object stored by Google.
So with this, I added the following ChangeHandler to my GWT FileUpload:
private void addChangeListener() {
Core.log("Selected file: " + uploader.getFilename());
uploader.addChangeHandler(new ChangeHandler() {
#Override
public void onChange(ChangeEvent event) {
MyApp.SERVICES.getUploadUrl(new SuccessAsyncCallback<String>() {
#Override
public void onSuccess(String uploadUrl) {
form.setAction(uploadUrl);
form.submit();
Core.log("Submitted form with upload url: " + uploadUrl);
}
});
}
});
}
Then in the servlet I have the GAE redirect to after uploads:
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws Exception {
BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
Map<String, List<BlobKey>> blobs = blobstoreService.getUploads(req);
// where 'uploader' is the name of the FileUploader (<input type='file'>) control on the client
List<BlobKey> blobKeys = blobs.get("uploader");
resp.getOutputStream().print(blobKeys.get(0).getKeyString());
}
Note!
GAE will throw a OutOfMemory exception when trying to get the uploaded blob's value if the FileUpload control doesn't have a name="whateveryouwantthenametobe" attribute defined, even if you tell it (using UiBinder) that the id is ui:field="nameofControl"

You cannot write to the local file system - you should take a look at the files api.

Related

Send a PDF as an attachment through Sendgrid

I'm using Sendgrid to send emails through an app on GAE. It's working fine, but I also want to be able to send PDFs as an attachment.
I'm not using Sendgrid.jar file in my project. I've just used Sendgrid.java. And this class has no methods by which i can add attachments. Can someone help me?
public static boolean sendEmail(String fromMail, String title, String toMail, String message) throws IOException {
Email from = new Email(fromMail);
String subject = title;
Email to = new Email(toMail);
Content content = new Content("text/html", message);
Mail mail = new Mail(from, subject, to, content);
Path file = Paths.get("file path");
Attachments attachments = new Attachments();
attachments.setFilename(file.getFileName().toString());
attachments.setType("application/pdf");
attachments.setDisposition("attachment");
byte[] attachmentContentBytes = Files.readAllBytes(file);
String attachmentContent = Base64.getMimeEncoder().encodeToString(attachmentContentBytes);
String s = Base64.getEncoder().encodeToString(attachmentContentBytes);
attachments.setContent(s);
mail.addAttachments(attachments);
SendGrid sg = new SendGrid("sendgrid api key");
Request request = new Request();
request.setMethod(Method.POST);
request.setEndpoint("mail/send");
request.setBody(mail.build());
Response response = sg.api(request);
if (response != null) {
return true;
} else {
return false;
}
}
Define above static method and call with relevant arguments as your program wants.
Here is the code of a servlet that sends a mail with a PDF as attachment, through Sendgrid:
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
....
ByteArrayOutputStream os = null;
try {
PDFGenerator pdfGenerator = new PDFGenerator(invoiceOut);
os = pdfGenerator.getPDFOutputStream();
} catch (Exception e) {
....
}
SendGrid sendgrid = new SendGrid(Constants.SENDGRID_API_KEY);
SendGrid.Email email = new SendGrid.Email();
email.addTo(....);
email.setFrom(....);
email.setFromName(....);
email.setSubject(....);
email.setHtml("......");
ByteBuffer buf = null;
if (os == null) {
//error...
} else {
buf = ByteBuffer.wrap(os.toByteArray());
}
InputStream attachmentDataStream = new ByteArrayInputStream(buf.array());
try {
email.addAttachment("xxxxx.pdf", attachmentDataStream);
SendGrid.Response response = sendgrid.send(email);
} catch (IOException e) {
....
throw new RuntimeException(e);
} catch (SendGridException e) {
....
throw new RuntimeException(e);
}
}
PDFGenerator is one of my classes in which getPDFOutputStream method returns the PDF as ByteArrayOutputStream.
I personally find it easier to directly construct the JSON request body as described in the API docs than to use Sendgrid's libraries. I only use the Sendgrid library for sending the request after I construct the JSON data myself.
When constructing the JSON data you need to specify at least a filename and the content (i.e., the PDF file). Make sure to Base64 encode the PDF file before adding it to the JASON data.
I'd include some code, but I do Python and not Java so not sure that would help.

Too many requests after uploading an image to google cloud storage

I watch a gcs bucket with watchbucket command. After that i am doing a upload. The watch command sends a notification to my servlet on app engine.
To be sure about that, i have a look at the logs. But it seems so, that some how the servlet keeps on getting request after request. Four times successfully and after that it gets an nullpointer exception. Why are there so many requests?
* EDIT *
On client side i use a meteorJS a Javascript framework. I added the extension slingshot to process the upload.
first i have to provide a the necessary info like acl, bucket, etc. like this:
Slingshot.createDirective('uploadSpotCover', Slingshot.GoogleCloud, {
bucket: 'upload_spot_cover',
GoogleAccessId: 'accessId',
acl: 'project-private',
maxSize: 0,
cacheControl: 'no-cache',
...
}
As you can see in line 153 slingshot uses a XMLHttpRequest to upload to Cloudstorage
https://github.com/CulturalMe/meteor-slingshot/blob/master/lib/upload.js#L144
On serverside my Servlet and it's logic look like this.
public class Upload extends HttpServlet {
private BucketNotification notification;
#Override
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
this.notification = getBucketNotification(req);
UploadObject object = new UploadObject(notification);
CloudStorageHandler gcs = new CloudStorageHandler();
BlobstoreHandler bs = new BlobstoreHandler();
ImageTransformHandler is = new ImageTransformHandler();
/** GET DATA FROM GCS **/
byte[] data = gcs.getFileFromGoogleCloudStorage(object.getGcsBucket(), object.getGcsPath());
//BlobKey bk = bs.createBlobKey(object.getGcsBucket(), object.getGcsPath());
/******************/
/** TRANSFORMATION **/
byte[] newImageData = is.resizePicture(data, 1200, 1200, "JPEG", 65, 0.5, 0.5);
/******************/
/** STORE NEW RESIZED FILE INTO GCS BUCKET **/
UploadObject tmp = new UploadObject(object.getGcsPath(), "JPEG", "beispiel", 1200, 1200);
tmp.setData(newImageData);
gcs.saveFileToGoogleCloudStorage(newImageData, "beispiel", object.getGcsPath(), "JPEG", "public-read");
/******************/
/** CREATE SERVING URL via BLOBKEY **/
BlobKey bk_neu = bs.createBlobKey("beispiel", object.getGcsPath());
String servingUrl = is.createServingUrlWithBlobkey(bk_neu);
/******************/
log("Blobkey: "+ bk_neu.getKeyString());
log("url: "+ servingUrl);
res.setStatus(200);
}
private BucketNotification getBucketNotification(HttpServletRequest req) {
BucketNotification notification = null;
String jsonString ="";
try {
jsonString ="";
BufferedReader in = new BufferedReader(new InputStreamReader(req.getInputStream()));
for (String buffer;(buffer = in.readLine()) != null;jsonString+=buffer + "\n");
in.close();
notification = new Gson().fromJson(jsonString, BucketNotification.class);
} catch (IOException e) {
log("Failed to decode the notification: " + e.getMessage());
return null;
}
return notification;
}
}
I wrapped the specific service methods like save file to cloudstorage in its own handlers.
Because I do not know what you are using to upload, I'm guessing now. Most file uploads upload stuff in bulks, so not the whole file at once, but in smaller chunks until everything is up. This would explain the multiple calls you are getting.
Can you show us the server and the client code? Maybe that way we could see the problem.

Error 404 when calling Google Cloud Endpoint API from Google Apps Script

I am trying to call a Google Cloud Endpoint API (developed on App Engine) via Google Apps Script. The endpoint is up and running, honestly I don't know which URL I should use but through Google Chrome Web Tools it looks like the URL is something like:
https://myapp.appspot.com/_ah/api/myendpointapi/v1/myEndPointMethod/
Along with API parameters directly included in the URL, separeted by slashes:
https://myapp.appspot.com/_ah/api/myendpointapi/v1/myEndPointMethod/param1value/param2value/...
Now, in order to call that API from Google App Script I am using the following code snippet:
function myFunction() {
var params =
{
"param1" : "param1value",
"param2" : "param2value",
};
var result = UrlFetchApp.fetch('https://myapp.appspot.com/_ah/api/myendpointapi/v1/myEndPointMethod/', params);
DocumentApp.getUi().alert(result);
}
However I always get a 404 error. If I have to be honest I don't even know if UrlFetchApp is the correct way of calling the API. I noticed this thread on StackOverflow but no one answered. What's the correct URL to use? Many thanks.
EDIT: Now I am trying with an API method which does not require any parameter. I found a way to call a specific URL (using method='get' as suggested by the answer below) but now I get a 401 error because it says I am not logged in. I believe I need to use some kind of OAuth parameter now. Any idea? I tryed using OAuthConfig but no luck with that as well :( From App Engine logs I can see the following error:
com.google.api.server.spi.auth.GoogleIdTokenUtils verifyToken: verifyToken: null
com.google.api.server.spi.auth.AppEngineAuthUtils getIdTokenEmail:
getCurrentUser: idToken=null
function myFunction() {
var result = UrlFetchApp.fetch('myurl', googleOAuth_());
result = result.getContentText();
}
function googleOAuth_() {
var SCOPE = 'https://www.googleapis.com/auth/drive';
var NAME = 'myAPIName';
var oAuthConfig = UrlFetchApp.addOAuthService(NAME);
oAuthConfig.setRequestTokenUrl('https://www.google.com/accounts/OAuthGetRequestToken?scope='+SCOPE);
oAuthConfig.setAuthorizationUrl('https://www.google.com/accounts/OAuthAuthorizeToken');
oAuthConfig.setAccessTokenUrl('https://www.google.com/accounts/OAuthGetAccessToken');
oAuthConfig.setConsumerKey('anonymous');
oAuthConfig.setConsumerSecret('anonymous');
return {oAuthServiceName:NAME, oAuthUseToken:'always'};
}
UrlFetchApp is the only way to call a Google Cloud Endpoints API at the moment. The second parameter to UrlFetchApp.fetch is a special key-value map of advanced options. To pass POST parameters, you need to do the following:
UrlFetchApp.fetch(url, {
method: 'post',
payload: {
"param1" : "param1value",
"param2" : "param2value",
}
});
I was fighting a similar (not the same) problem, when testing feasibility of a GCM backed by EndPoints server. Basically testing if it is possible to get the Google Spreadsheet Appscript to send notification to an Android device. Please bear with me, the following explanation may be a bit convoluted;
Starting with a standard 'Cloud Messaging for Android', backed by the 'App Engine Backend with Google Cloud Messaging', I managed to build a test system that would send messages between Android devices (Github here).
Here is a VERY sparse EndPoints server code that handles register / un-register Android devices, as well as reporting registered devices and sending a message to a list of registered devices.
WARNING: This is not a production quality code, it is stripped of any logging, error handling in order to keep it short.
#Api( name = "gcmEP", version = "v1",
namespace = #ApiNamespace(ownerDomain = "epgcm.example.com", ownerName = "epgcm.example.com", packagePath = "" )
)
public class GcmEP {
#ApiMethod(name = "registToken")
public void registToken(#Named("token") String token) {
if (ofy().load().type(TokenRec.class).filter("token", token).first().now() == null) {
ofy().save().entity(new TokenRec(token)).now();
}
}
#ApiMethod(name = "unregToken")
public void unregToken(#Named("token") String token) {
TokenRec record = ofy().load().type(TokenRec.class).filter("token", token).first().now();
if (record != null) {
ofy().delete().entity(record).now();
}
}
#ApiMethod(name = "listTokens")
public CollectionResponse<TokenRec> listTokens() {
return CollectionResponse.<TokenRec>builder().setItems(ofy().load().type(TokenRec.class).list()).build();
}
#ApiMethod(name = "sendMsg")
public void sendMsg(#Named("message") String message) throws IOException {
if (message != null && message.length() > 0) {
Sender sender = new Sender(System.getProperty("gcm.api.key"));
Message msg = new Message.Builder().addData("message", message).build();
for (TokenRec record : ofy().load().type(TokenRec.class).list()) {
Result result = sender.send(msg, record.getToken(), 4);
if (result.getMessageId() != null) {
// handle CanonicalRegistrationId
} else {
// handle errors, delete record
}
}
}
}
}
Android code for registration and message sending is shown here, even if it is not relevant.
GcmEP mRegSvc;
String mToken;
// register device on EndPoints backend server
private void registerMe() {
new Thread(new RegisterMe(this)).start();
}
private class RegisterMe implements Runnable {
Activity mAct;
public RegisterMe(Activity act) { mAct = act; }
public void run() {
String senderId = null;
if (mAct != null) try {
if (mRegSvc == null) {
mRegSvc = new GcmEP
.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null).setRootUrl(UT.ROOT_URL).build();
}
senderId = getString(R.string.gcm_defaultSenderId);
mToken = InstanceID.getInstance(mAct).getToken(senderId, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
mRegSvc.registToken(mToken).execute();
GcmPubSub.getInstance(mAct).subscribe(mToken, "/topics/global", null); // subscribing to all 'topics' from 'mToken'
} catch (IOException e) { e.printStackTrace(); }
}
}
// send message to EndPoints backend server
new Thread(new Runnable() {
#Override
public void run() {
if (mRegSvc != null) try {
mRegSvc.sendMsg("hello").execute();
} catch (IOException e) { e.printStackTrace(); }
}
}).start();
// receive GCM message
public class GcmListenSvc extends GcmListenerService {
#Override
public void onMessageReceived(String senderId, Bundle data) {
Log.i("_X_", data.getString("message"));
}
}
What is relevant, thought, there is also an APIs Explorer created for the project, that can be used to send messages to your Android device from any browser.
If you use this Explorer, you can see the GET, POST requests for your EndPoints backend server, i.e.
list all registered devices:
GET https://epgcm.appspot.com/_ah/api/gcmEP/v1/tokenrec?fields=items
send a message to all registered devices:
POST https://epgcm.appspot.com/_ah/api/gcmEP/v1/sendMsg/Hello%20World!
Now, you can use this knowledge to send messages to your Android device from an AppScript code as shown:
Version 1: Get list of registered devices and send a GCM message to all of them (or a filtered set).
function sendMsg() {
var msg = 'test from CODE.GS';
var url = 'https://epgcm.appspot.com/_ah/api/gcmEP/v1/tokenrec?fields=items';
var params = { method : 'get'};
var response = UrlFetchApp.fetch(url, params);
var data = JSON.parse(response.getContentText());
var regIds = [];
for (i in data.items)
regIds.push(data.items[i].token);
var payload = JSON.stringify({
'registration_ids' : regIds,
'data' : { 'message' : msg }
});
var params = {
'contentType' : 'application/json',
'headers' : {'Authorization' : 'key=AIza............................'},
'method' : 'post',
'payload' : payload
};
url = 'https://android.googleapis.com/gcm/send';
UrlFetchApp.fetch(url, params);
}
This version relies on code from an old YouTube video, and I don't know if the call to 'android.googleapis.com' is still supported (but it works).
Version 2: Use the EndPoints's 'sendMsg' directly.
function sendMsg() {
var msg = 'test from CODE.GS';
var params = { method : 'post'};
var url = 'https://demoepgcm.appspot.com/_ah/api/gcmEP/v1/sendMsg/' + encodeURIComponent(msg.trim());
UrlFetchApp.fetch(url, params);
}
I have to admit I've never written a line of JavaScript code before, so it may not be up-to-par, but I made it work as a 'proof of concept'.
I would like to get feedback about this problem from people-who-know, since there is so little published info on this specific issue.

Apache Camel server app receiving a multipart form POST (file upload)

I'm using Camel servlet component in order to receive xml documents and now I also need to receive files (jpegs, gifs, etc). So here is how my client app is sending a file:
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
public class HttpClientUploadHelper {
public boolean upload(final File file, final String url) {
boolean wasSent = false ;
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
MultipartEntity entity = new MultipartEntity();
entity.addPart(file.getName(), new FileBody(file));
post.setEntity(entity);
try {
HttpResponse response = client.execute(post);
wasSent = response.getStatusLine().getStatusCode()==200;
} catch (Exception e) {
}
return wasSent;
}
}
my Camel Processor then extracts the HttpServletRequest this way:
HttpServletRequest req = exchange.getIn().getHeader(Exchange.HTTP_SERVLET_REQUEST, HttpServletRequest.class);
then I have this method to finally parse and save the file:
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils
... class declaration, body, etc...
void parseAndSaveFile(final HttpServletRequest req) throws Exception {
// Check that we have a file upload request
boolean isMultipart = ServletFileUpload.isMultipartContent(req);
// Create a factory for disk-based file items
FileItemFactory factory = new DiskFileItemFactory();
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
// Parse the request
FileItemIterator receivedFiles = upload.getItemIterator(req);
while (receivedFiles.hasNext()) {
FileItemStream file = receivedFiles.next();
if (file.isFormField()) {
System.out.println("WTF?");
} else {
String fileName = file.getName();
File uploadedFile = new File("/home/myuser/" + fileName);
FileOutputStream out = new FileOutputStream(uploadedFile);
IOUtils.copy(file.openStream(), out);
}
}
}
when I use above code within Camel, that isMultipart flag is "true" but that receivedFiles iterator doesn't contains any element. When I use above code within another project with just a plain servlet, the code works. In both ways I'm using jetty as the web container.
So is there any other way to extract the file name and it's content within my camel processor ?
Thanks!
Since you're using Jetty, have you considered using the included MultipartFilter instead of the FileUpload project? Super clean and easy to use.
From the javadoc:
"This class decodes the multipart/form-data stream sent by a HTML form that uses a file input item. Any files sent are stored to a temporary file and a File object added to the request as an attribute. All other values are made available via the normal getParameter API and the setCharacterEncoding mechanism is respected when converting bytes to Strings."
Does this help?
public void process(Exchange exchange) throws Exception {
Message in = exchange.getIn();
Set names = in.getAttachmentNames();
for(String n: names) {
System.out.println("attachment "+n);
DataHandler h = in.getAttachment(n);
if(h!=null) {
try {
Object o = h.getContent();
System.out.println(o);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
if(!names.isEmpty())
return;
}

How can google app engine create new contacts?

I'm developing a membership sign up app for an organization on Google App Engine, for new members, they can use a sign up page to become a member, is there a way in Google App Engine to add new members as gmail contacts ? So each time a new user clicks a submit button with his info, a new gmail contact is auto generated and added to my contact list [ my gmail address is registered with the GAE app ].
Here is some of my code try to do that, but it doesn't add new contacts each a submit button is pressed :
String Add_New_Contact_Url="https://www.google.com/m8/feeds/contacts/default/full";
protected void processRequest(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException
{
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=UTF-8"); // UTF-8 GB18030
PrintWriter out=response.getWriter();
String Email=request.getParameter("Email");
if (Email==null || Email.trim().length()<1)
{
StrBuf=new StringBuffer("<Html><Head><Title>Signup</Title></Head>\n<Body>\n");
StrBuf.append("<P><Br><P><Br><P>\n");
StrBuf.append("<Table Border=1 Align=Center Cellpadding=8 Cellspacing=1><Tr Bgcolor=\"#0088FF\" Colspan=2><Th><Font Color=White>Sign up</Font></Th></Tr></Table>\n<P>\n");
StrBuf.append("<Center>\n");
StrBuf.append("<Form Name=Singles_Club_Signup_Form>\n");
StrBuf.append("<Table Border=1 Cellpadding=6 Cellspacing=1>\n");
...
StrBuf.append("<Tr><Td Align=Right><B><Font Size=3 Color=#0066FF>Email</Font></B></Td><Td><Input type=text name=Email size=36 /></Td></Tr>\n");
...
StrBuf.append("</Table>\n");
StrBuf.append("<P><Br><P>\n");
StrBuf.append("<Input type=submit value=Sign_Up/>\n");
StrBuf.append("</Form>\n");
StrBuf.append("</Center>\n");
StrBuf.append("</Body>\n</Html>");
}
else
{
try
{
LinkedHashMap<String,String> Key_Value_Pairs=new LinkedHashMap<String,String>();
String A_Contact=createContact(Email);
Key_Value_Pairs.put("A",A_Contact);
getFromUrlDoPost(Add_New_Contact_Url,Key_Value_Pairs); // Create new contact in Gmail account
}
catch (Exception e) { out.println(e.toString()); }
finally { if (pm!=null) pm.close(); }
}
}
String createContact(String Email)
{
return "<atom:entry xmlns:atom='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'>\n"+
"<atom:category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/contact/2008#contact' />\n"+
"<gd:name>\n"+
"<gd:givenName>AAA</gd:givenName>\n"+
"<gd:familyName>BBB</gd:familyName>\n"+
"<gd:fullName>AAA BBB</gd:fullName>\n"+
"</gd:name>\n"+
"<atom:content type='text'>Notes</atom:content>\n"+
"<gd:email rel='http://schemas.google.com/g/2005#work' primary='true' address='"+Email+"' displayName='E. Bennet' />\n"+
"<gd:email rel='http://schemas.google.com/g/2005#home' address='liz#example.org' />\n"+
"<gd:phoneNumber rel='http://schemas.google.com/g/2005#work' primary='true'>\n"+
"(206)555-1212\n"+
"</gd:phoneNumber>\n"+
"<gd:phoneNumber rel='http://schemas.google.com/g/2005#home'>\n"+
"(206)555-1213\n"+
"</gd:phoneNumber>\n"+
"<gd:im address='liz#gmail.com' protocol='http://schemas.google.com/g/2005#GOOGLE_TALK' primary='true' rel='http://schemas.google.com/g/2005#home' />\n"+
"<gd:structuredPostalAddress rel='http://schemas.google.com/g/2005#work' primary='true'>\n"+
"<gd:city>Mountain View</gd:city>\n"+
"<gd:street>1600 Amphitheatre Pkwy</gd:street>\n"+
"<gd:region>CA</gd:region>\n"+
"<gd:postcode>94043</gd:postcode>\n"+
"<gd:country>United States</gd:country>\n"+
"<gd:formattedAddress>\n"+
"1600 Amphitheatre Pkwy Mountain View\n"+
"</gd:formattedAddress>\n"+
"</gd:structuredPostalAddress>\n"+
"</atom:entry>";
}
StringBuffer getFromUrlDoPost(String A_Url,LinkedHashMap Key_Value_Pairs) throws MalformedURLException,IOException
{
StringBuffer Text_Out=new StringBuffer(""),Text_In=new StringBuffer("");
String data="",key,value,inputLine;
try // Sending a POST Request Using a URL
{
// Construct data -- List the entries
for (Iterator it=Key_Value_Pairs.keySet().iterator();it.hasNext();)
{
key=it.next().toString();
value=Key_Value_Pairs.get(key).toString();
if (data.length()==0) data=URLEncoder.encode(key,"UTF-8")+"="+URLEncoder.encode(value,"UTF-8");
else data+="&"+URLEncoder.encode(key,"UTF-8")+"="+URLEncoder.encode(value,"UTF-8");
}
// Send data
URLConnection conn=new URL(A_Url).openConnection();
conn.setRequestProperty("Content-Type","application/atom+xml");
conn.setDoOutput(true);
OutputStreamWriter wr=new OutputStreamWriter(conn.getOutputStream());
wr.write(data);
wr.flush();
Text_In.setLength(0);
// Get the response
BufferedReader rd=new BufferedReader(new InputStreamReader(conn.getInputStream()));
while ((inputLine=rd.readLine()) != null) Text_In.append(inputLine+"\n");
wr.close();
rd.close();
}
catch (Exception e) { }
return Text_In;
}
It doesn't cause error either, what did I do wrong ? I suspect this line :
Key_Value_Pairs.put("A",A_Contact);
Because I don't know what to put in the place of "A" ?
Your users can authorize your application (via OAuth) to interact with their gmail contact list via the Contacts Data API.
I found out why : don't need to include google-collect-*.jar, source of error.

Resources