Saturday, March 17, 2012

GWT: Creating a simple File hosting site

GWT : Creating a simple file hosting site


The free hosting site that I used to store my source code was gone without warning.
Thus, I no longer trust these free sites anymore.

To store my android tutorial source code, I decided to create a simple file hosting so I can upload my source codes.
Further, since the app-engine service by google is free I decided to use it.

Tools/Libraries/Framework used:

1. Google App Engine
2. GWT
3. Apache File Upload

Links to get started with Google App Engine (GAE) and Google web Toolkit (GWT)

1. GAE http://code.google.com/webtoolkit/doc/latest/tutorial/gettingstarted.html
2. GWT http://code.google.com/webtoolkit/doc/latest/tutorial/RPC.html
3. AppEngine http://code.google.com/appengine/docs/java/gettingstarted/
4. AppEngine-JPA http://code.google.com/appengine/docs/java/datastore/jpa/overview.html
5. TableLess Layout for GWT HTML - http://www.w3schools.com/html/html_layout.asp

I. Defining the BLOB object for the file hosting service.
@Entity
public class FileBlob implements Serializable {
private static final long serialVersionUID = -5835124824181798205L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Blob content;
private String filename;
private String contentType;

II. Creating The Front End
  Create simple class that extends a vertical panel then add a button to display the pop-up upload dialog.

public void onClick(ClickEvent event) {
if (event.getSource() == btnUpload) {
DialogBox innerDialogBox = new BlobFileUpload(this);
// innerDialogBox.center();
innerDialogBox.show();
}
}


Create the CellTable to display the file details. http://code.google.com/webtoolkit/doc/latest/DevGuideUiCellTable.html

To enable pagination for the celltable, see GWT SimplePager.

III. Creating the BlobFileUpload dialogbox

public class BlobFileUpload extends DialogBox {
public BlobFileUpload(DownloadPanel downloadPanel) {
super();
this.downloadPanel = downloadPanel;
clear();
setText("Upload File");
//Set the servlet that will handle multi-part requests.
formPanel.setAction("/downloads/fileupload");
formPanel.setEncoding(FormPanel.ENCODING_MULTIPART);
//Set method post
formPanel.setMethod(FormPanel.METHOD_POST);
//Initialize the file upload object
fileUpload = new FileUpload();
fileUpload.setName("upload");
//Add click handler to the button, perform simple validation then call formPanel.submit
btnSubmit.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
lblLoading.setText("Uploading Please Wait");
if(!fileUpload.getFilename().trim().equals("")) {
formPanel.submit();
} else {
Window.alert("No file selected.");
}
}
});
btnClose.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
BlobFileUpload.this.hide();
}
});
verticalPanel.add(fileUpload);
verticalPanel.add(lblLoading);
controlPanel.add(btnSubmit);
controlPanel.add(btnClose);
verticalPanel.add(controlPanel);
//I don't know what this does but I saw this on some tutorial before.
formPanel.addSubmitHandler(new FormPanel.SubmitHandler() {
public void onSubmit(SubmitEvent event) {
}
});
//Callback handler when uploading is completed.
formPanel.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
public void onSubmitComplete(SubmitCompleteEvent event) {
String msg = event.getResults().replace("
", "").replace(
"
", "");
Window.alert("Message : " + msg);
lblLoading.setText("");
BlobFileUpload.this.downloadPanel.initData();
BlobFileUpload.this.hide();
}
});
formPanel.setWidget(verticalPanel);
add(formPanel);
}

}



IV. Creating the FileUploadServlet

Use the sample code for Apache FileUpload.
I just retrieved the filename, contact type and the content.
Then used these values to set the FileBlob object.

 public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
printf("doPost");
if (!isMultipart) {
printf("!isMultipart");
} else {
ServletFileUpload upload = new ServletFileUpload();
upload.setSizeMax(10*1024*1024);
try {
FileItemIterator iterator = upload.getItemIterator(request);
while (iterator.hasNext()) {
printf("(iterator.hasNext())");
FileItemStream item = iterator.next();
InputStream in = item.openStream();
if (item.isFormField()) {
System.out.println("if (item.isFormField())");
System.out.println("FieldName=" + item.getFieldName());
System.out.println("Name=" + item.getName());

} else {
System.out.println("} else {");
System.out.println("FieldName=" + item.getFieldName());
System.out.println("Name=" + item.getName());
System.out.println("contentType=" + item.getContentType());
try {
byte[] byteData = IOUtils.toByteArray(in);
FileBlob fileBlob = new FileBlob(item.getName(), item.getContentType(), byteData);
fileBlobDao.create(fileBlob);
printf(item.getName() + " uploaded successful");
out.println(item.getName() + " uploaded successful");
} catch (Exception ex) {
ex.printStackTrace();
out.println("ERROR " + ex.getMessage());
} finally {
IOUtils.closeQuietly(in);
}
}
}
} catch (Exception e) {
//out.println("ERROR " + e.getMessage());
//e.printStackTrace();
out.println("Upload Failed.. The size of the file is greater than 10MB");
printf("Upload Failed.. The size of the file is greater than 10MB");
}
}
}



V. creating the FileBlob Data Access Object

Creating a BLOB as with all object is straightforward in AppEngine-JPA.

public String create(FileBlob fileBlob) {
String message = null;
EntityManager entityManager = null;
try {
System.out.println("Creating : " + fileBlob.getFilename());
entityManager = EMF.get().createEntityManager();
entityManager.persist(fileBlob);
message = fileBlob.getId() + " succesfully created.";
} catch (Exception ex) {
ex.printStackTrace();
message = "Error : " + ex.getMessage();
} finally {
if (entityManager != null) {
entityManager.close();
}
}
return message;
}



VI. Retrieving Files using FileDetail.

Since we do not need all fields to be displayed on the screen, a FileDetail object which holds only what is neccessary.
@Override
public ArrayList retreiveAll() {
ArrayList fileBlobs = fileBlobDao.retrieveAll();
ArrayList listFileDetail = new ArrayList();
for(FileBlob fb : fileBlobs) {
FileDetail fd = new FileDetail();
fd.setId(fb.getId());
fd.setFilename(fb.getFilename());
listFileDetail.add(fd);
}
return listFileDetail;
}


VII. Creating the DownloadServlet

Convert the BLOB to bytes

public class FileDownloadServlet extends HttpServlet {

private static final long serialVersionUID = -2004901543318306888L;

private FileBlobDao fileBlobDao = new FileBlobDao();
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String id = request.getParameter("id");
Long lId = new Long(id);
FileBlob fileBlob = fileBlobDao.findById(lId);
if(fileBlob != null) {
String contentType = fileBlob.getContentType();
if(contentType != null && !contentType.trim().equals("")) {
response.setContentType(contentType);
} else {
response.setContentType("application/octet-stream");
}
response.setHeader( "Content-Disposition", "attachment; filename=\"" + fileBlob.getFilename() + "\"" );
System.out.println("FileBlob:"+fileBlob.getContent().getBytes().length);
response.setContentLength((int)fileBlob.getContent().getBytes().length);
response.getOutputStream().write(fileBlob.getContent().getBytes());
response.getOutputStream().flush();
}
response.getOutputStream().flush();
}
}


VIII. Configurations

Don't forget to configure web.xml, persistence.xml.

IX. See the application in action downloads.androidph.com

Find file-hosting-v1.zip or click here to download this tutorial's source-code.


Monday, March 12, 2012

Announcement : AndroidPH.com Code Not Updated

Hi Friends,

Please bear with me while I try to find time to update the code which was created during Android 1.5.

I am prioritizing tutorial for Android Camera. I have one idea for a practical use for Android Camera, I'll try to add it in the next couple of weeks.

Thanks.

GWT SimplePager on CellTable is not Updating

The code below works on initialization, however if you add new data, it does not display the updated row.

Previous Code :
CellTable table = new CellTable();
SimplePager.Resources pagerResources = GWT.create(SimplePager.Resources.class);
pager = new SimplePager(TextLocation.CENTER, pagerResources, false, 0, true);
pager.setDisplay(table);
pager.setPageSize(10);
table.setPageSize(10);
ListDataProvider dataProvider = new ListDataProvider();
dataProvider.addDataDisplay(table);
List list = dataProvider.getList();
for (Carrier contact : data) {
list.add(contact);
}


Fix :
pager.startLoading();

Current Code :
CellTable table = new CellTable();
SimplePager.Resources pagerResources = GWT.create(SimplePager.Resources.class);
pager = new SimplePager(TextLocation.CENTER, pagerResources, false, 0, true);
pager.setDisplay(table);
pager.setPageSize(10);
table.setPageSize(10);
pager.startLoading();
ListDataProvider dataProvider = new ListDataProvider();
dataProvider.addDataDisplay(table);
List list = dataProvider.getList();
for (Carrier contact : data) {
list.add(contact);
}

Thursday, January 5, 2012

Android Custom Database ListAdapters

On the ListActivity class :

ListPatientCursorAdapter listAdapter = new ListPatientCursorAdapter(this, R.layout.patient_list, cursor);
setListAdapter(listAdapter);
startManagingCursor(cursor);


Custom List Adapter :

class ListPatientCursorAdapter extends ResourceCursorAdapter {

public ListPatientCursorAdapter(Context context, int layout, Cursor c) {
super(context, layout, c);
}

@Override
public View newView(Context context, Cursor cur, ViewGroup parent) {
LayoutInflater li = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return li.inflate(R.layout.patient_list_row, parent, false);
}


@Override
public void bindView(View v, Context context, final Cursor _c) {
TextView tvId = (TextView)v.findViewById(R.id.tvId);
final Integer id = _c.getInt(_c.getColumnIndex(Patient.PatientField.ID));
TextView tvFirstName = (TextView) v.findViewById(R.id.tvFirstName);
tvFirstName.setText(_c.getString(_c
.getColumnIndex(Patient.PatientField.FIRSTNAME)));

TextView tvMiddleName = (TextView) v
.findViewById(R.id.tvMiddleName);
tvMiddleName.setText(_c.getString(_c
.getColumnIndex(Patient.PatientField.MIDDLENAME)));

TextView tvLastName = (TextView) v.findViewById(R.id.tvLastName);
tvLastName.setText(_c.getString(_c
.getColumnIndex(Patient.PatientField.LASTNAME)));

TextView tvLastUpdate = (TextView) v
.findViewById(R.id.tvLastUpdate);

CheckBox cbFollowUp = (CheckBox) v.findViewById(R.id.cbFollowUp);
cbFollowUp
.setChecked(_c.getInt(_c
.getColumnIndex(Patient.PatientField.FOR_FOLLOWUP)) == 0 ? false
: true);

Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(_c.getLong(_c
.getColumnIndex(Patient.PatientField.UPDATE_DATE)));

tvLastUpdate.setText(sdf.format(cal.getTime()));

v.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
processSelectedId(id);
}
});
}
}


List View :

android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:divider="#FFFFFF"
android:dividerHeight="0sp"
android:scrollbars="none" />
android:id="@id/android:empty"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5px"
android:gravity="center"
android:text="No Patient Record." >




List Row :



android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
android:id="@+id/tvId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:visibility="gone"/>
android:id="@+id/llPatient"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
android:id="@+id/tvLastName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Puti"
android:textAppearance="?android:attr/textAppearanceLarge" />
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" "
android:textAppearance="?android:attr/textAppearanceMedium" />
android:id="@+id/tvFirstName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Kyle"
android:textAppearance="?android:attr/textAppearanceMedium" />

android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" "
android:textAppearance="?android:attr/textAppearanceMedium" />

android:id="@+id/tvMiddleName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Amousy"
android:textAppearance="?android:attr/textAppearanceMedium" />

android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Last Update"
android:textAppearance="?android:attr/textAppearanceMedium" />
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" "
android:textAppearance="?android:attr/textAppearanceMedium" />
android:id="@+id/tvLastUpdate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Last Update" />

android:id="@+id/cbFollowUp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:enabled="false"
android:text="For Follow Up" />

Android SQLite Primary Key Auto Increment

WRONG :
CREATE TABLE PERSON (ID INTEGER PRIMARY KEY AUTOINCREMENT,
FIRSTNAME TEXT,
LASTNAME TEXT)

WRONG :
CREATE TABLE PERSON (ID INT PRIMARY KEY AUTOINCREMENT,
FIRSTNAME TEXT,
LASTNAME TEXT)

CORRECT :
CREATE TABLE PERSON (ID INTEGER PRIMARY KEY,
FIRSTNAME TEXT,
LASTNAME TEXT)

Java Code To Insert (Do Not Set ID field):
ContentValues values = new ContentValues();
values.put("FIRSTNAME", "Java");
values.put("LASTNAME", "Padawan");


Then on your SQLiteDatabase instance do :
sqlDatabase.insert("PERSON" null, values);

Email

java.padawan@androidph.com