Showing posts with label file. Show all posts
Showing posts with label file. Show all posts
Wednesday, March 11, 2015
Building an Enterprise File Server on Google Drive
Editors note: This is a guest post by Thomas Gerber. Thomas is the CTO of Altirnao, the developer of the AODocs document management app on the Google Apps Marketplace. Thomas tells the story of his application and provides some tips for developers considering integrating with Google Apps and launching on the Marketplace. — Arun Nagarajan
Google Drive is increasingly popular in the enterprise, and many organizations would like to leverage it as a replacement for their existing on-premises file servers. Moving physical file servers to Drive provides many benefits, such as reliability, cost-effectiveness and the ability to access the files from anywhere and any device. However, the storage structure of Google Drive, where files are owned by many different users, is significantly different from the centralized organization of a file server, where everything is under the control of a small number of system administrators.
To address this problem, AODocs uses the Google Drive API to automatically transfer the ownership of files to a system account, and thus create a sort of “managed area” within Google Drive. With the Google Drive API, AODocs has complete control over the folder structure and the permissions of files owned by this system account. AODocs can be deployed in one click from the Google Apps Marketplace, which makes our application visible (and easy to try out!) for every Google Apps administrator in the world.

Companies who want to store their files on Google Drive may be concerned about losing control of their data (e.g. access to files being lost when an employee leaves the company) and controlling sharing permissions.
AODocs uses a single system account (i.e. a Google Apps account belonging to the customer’s domain, but not used by any human person) as a “proxy” to control the files. When a Google Drive files is added to an AODocs library, the ownership of the file is transferred to the AODocs system account and the file’s writersCanShare attribute is set to false, so that only AODocs is able to modify the file’s permissions afterwards.
To change the ownership of the file, we check if the system account can already access the file, and then either insert a new “owner” permission on it or use the Permissions.update method with the transferOwnership flag:
Since all the files are owned by the system account, AODocs completely controls the lifecycle of the file (how they are created, in which folder they are located, who can change their permissions, who can delete them, etc). AODocs can thus provide higher-level document management features on top of Google Drive, such as configuring the retention time of deleted files, limiting external sharing to a whitelist of “trusted external domains”, or recording an audit log of file modifications.
As illustrated in the code snippet above, AODocs relies on the Google Drive API to perform all the operations on the managed files. The main challenge we had when using the Drive API was to properly handle all the error codes returned by the API calls, and make sure we make the difference between fatal errors that should not be tried again (for example, permission denied on a file) and the temporary errors that should be re-tried later (for example, “rate limit exceeded”). To handle that, we have encapsulated all our Google Drive API calls (we are using the Java client library) into a class named RetriableTask, which is responsible for handling the non-fatal errors and automatically retry the API calls with the proper exponential back-off. Here is a simplified version:
AODocs is designed to work seamlessly with Google Drive, and our top priority is to leverage all the integration possibilities offered by the Google APIs. We are very excited to see that new features are added very often in the Admin SDK, the Google+ API, the Drive API that will allow AODocs to provide more options to system administrators and improve the experience for our end users.
Read more »
Google Drive is increasingly popular in the enterprise, and many organizations would like to leverage it as a replacement for their existing on-premises file servers. Moving physical file servers to Drive provides many benefits, such as reliability, cost-effectiveness and the ability to access the files from anywhere and any device. However, the storage structure of Google Drive, where files are owned by many different users, is significantly different from the centralized organization of a file server, where everything is under the control of a small number of system administrators.
To address this problem, AODocs uses the Google Drive API to automatically transfer the ownership of files to a system account, and thus create a sort of “managed area” within Google Drive. With the Google Drive API, AODocs has complete control over the folder structure and the permissions of files owned by this system account. AODocs can be deployed in one click from the Google Apps Marketplace, which makes our application visible (and easy to try out!) for every Google Apps administrator in the world.
Companies who want to store their files on Google Drive may be concerned about losing control of their data (e.g. access to files being lost when an employee leaves the company) and controlling sharing permissions.
AODocs uses a single system account (i.e. a Google Apps account belonging to the customer’s domain, but not used by any human person) as a “proxy” to control the files. When a Google Drive files is added to an AODocs library, the ownership of the file is transferred to the AODocs system account and the file’s writersCanShare attribute is set to false, so that only AODocs is able to modify the file’s permissions afterwards.
To change the ownership of the file, we check if the system account can already access the file, and then either insert a new “owner” permission on it or use the Permissions.update method with the transferOwnership flag:
public void changeOwner(String user, String fileId, String newOwner) {
// Find what is the current permission of the new owner on the file
Permission newOwnerPermission = null;
PermissionList permissionList = RetriableTask.execute(new DrivePermissionListTask(drive.permissions().list(fileId)));
newOwnerPermission = findPermission(permissionList, newOwner);
if (newOwnerPermission == null) {
// New owner is not in the list, we need to insert it
newOwnerPermission = new Permission();
newOwnerPermission.setValue(newOwner);
newOwnerPermission.setType("user");
newOwnerPermission.setRole("owner");
Drive.Permissions.Insert insert = drive.permissions().insert(fileId, newOwnerPermission);
RetriableTask.execute(new DrivePermissionInsertTask(insert));
} else {
// New owner is already in the list, update the existing permission
newOwnerPermission.setRole("owner");
Drive.Permissions.Update update = drive.permissions().update(fileId, newOwnerPermission.getId(), newOwnerPermission);
update.setTransferOwnership(true);
RetriableTask.execute(new DrivePermissionUpdateTask(update));
}
}
Since all the files are owned by the system account, AODocs completely controls the lifecycle of the file (how they are created, in which folder they are located, who can change their permissions, who can delete them, etc). AODocs can thus provide higher-level document management features on top of Google Drive, such as configuring the retention time of deleted files, limiting external sharing to a whitelist of “trusted external domains”, or recording an audit log of file modifications.
As illustrated in the code snippet above, AODocs relies on the Google Drive API to perform all the operations on the managed files. The main challenge we had when using the Drive API was to properly handle all the error codes returned by the API calls, and make sure we make the difference between fatal errors that should not be tried again (for example, permission denied on a file) and the temporary errors that should be re-tried later (for example, “rate limit exceeded”). To handle that, we have encapsulated all our Google Drive API calls (we are using the Java client library) into a class named RetriableTask, which is responsible for handling the non-fatal errors and automatically retry the API calls with the proper exponential back-off. Here is a simplified version:
public class RetriableTaskimplements Callable {
[...]
private final Callabletask;
[...]
@Override public T call() {
T result = null;
try {
startTime = System.currentTimeMillis();
result = task.call();
} catch (NonFatalErrorException e) {
if (numberOfTriesLeft > 0) {
// Wait some time, using exponential back-off in case of multiple attempts
Thread.sleep(getWaitTime());
// Try again
result = call();
} else {
// Too many failed attempts: now this is a fatal error
throw new RetryException();
}
} catch (FatalErrorException e) {
// This one should not be retried
Throwables.propagate(e);
}
return result;
}
AODocs is designed to work seamlessly with Google Drive, and our top priority is to leverage all the integration possibilities offered by the Google APIs. We are very excited to see that new features are added very often in the Admin SDK, the Google+ API, the Drive API that will allow AODocs to provide more options to system administrators and improve the experience for our end users.
| Thomas Gerber profile Thomas is the CTO of Altirnao. Before founding Altirnao, Thomas has led a team of senior technologists and architects on High Availability/High Performance implementations of enterprise software. |
Thursday, February 5, 2015
PhoneGap tutorial parsing xml file and displaying results on android screen
Parsing xml file using JavaScript for PhoneGap Applications.
Hi Friends i am going to show how to parse xml file using javascript without using using any jQuery Mobile Here is the xml file i am going to parse :
MakeMyTrip.com
MakeMyTrip.com is one of the good website providing Travel services to book oonline Flight,Hotel,Train and Bus tickets with guranteed lowest prices and provides new deals , offers and discount coupons every week and help you save money upto 20% while you travel.
travellogos/makemytrip-logo.jpg
GoIbibo.com
GoIbibo.com is one of the good website providing Travel services to book oonline Flight,Hotel,Train and Bus tickets with guranteed lowest prices and provides new deals , offers and discount coupons every week and help you save money upto 20% while you travel.
travellogos/goibibo_logo.png
Abhibus.com
Abhibus.com is one of the good website providing Travel services to book oonline Flight,Hotel,Train and Bus tickets with guranteed lowest prices and provides new deals , offers and discount coupons every week and help you save money upto 20% while you travel.
travellogos/abhibus-logo.png
Travelyaari.com
Travelyaari.com is one of the good website providing Travel services to book oonline Flight,Hotel,Train and Bus tickets with guranteed lowest prices and provides new deals , offers and discount coupons every week and help you save money upto 20% while you travel.
travellogos/travelyaari-com-logo-w240.png
Redbus.in
Redbus.com is one of the good website providing Travel services to book oonline Flight,Hotel,Train and Bus tickets with guranteed lowest prices and provides new deals , offers and discount coupons every week and help you save money upto 20% while you travel.
travellogos/logo_bc9228d_163.jpg
Expedia.co.in
Expedia.co.in is one of the good website providing Travel services to book oonline Flight,Hotel,Train and Bus tickets with guranteed lowest prices and provides new deals , offers and discount coupons every week and help you save money upto 20% while you travel.
travellogos/expedia-logo.png
Other websites
We Provide more websites that offer good Travel services to book oonline Flight,Hotel,Train and Bus tickets with guranteed lowest prices and provides new deals , offers and discount coupons every week and help you save money upto 20% while you travel.
travellogos/travel-agency-logos.jpg
function travel(){
if (window.XMLHttpRequest)
{ // code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{ // code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("GET","Travel.xml",false);
xmlhttp.send();
xmlDoc=xmlhttp.responseXML;
travels = xmlDoc.getElementsByTagName("website");
alert("travels:"+travels.length);
var websites = [];
var description = [];
var logos = [];
for(var travel=0;travelwebsitename=travels[travel].getElementsByTagName("sitename")[0].childNodes[0].nodeValue;
var websites.push(websitename);
var des=travels[travel].getElementsByTagName("Description")[0].childNodes[0].nodeValue;
description.push(des);
var images = travels[travel].getElementsByTagName("Image")[0].childNodes[0].nodeValue;
logos.push(images);
}
var listview = document.getElementById("container");
var ul = document.createElement("ul");
for(var i=0;ivar livalue= document.createTextNode(websites[i]);
var desvalue = document.createTextNode(description[i]);
var li = document.createElement("li");
var table = document.createElement("table");
var table1 = document.createElement("table");
var tr1 = document.createElement("tr");
var td1 = document.createElement("td");
var img = new Image();
img.src= logos[i];
img.setAttribute("width",60);
img.setAttribute("height",30);
img.setAttribute(onclick, "test()");
td1.appendChild(img);
tr1.appendChild(td1);
var tr2 = document.createElement("tr");
var td2 = document.createElement("td");
var td3 = document.createElement("td");
td2.appendChild(livalue);
td3.appendChild(desvalue);
tr1.appendChild(td2);
tr2.appendChild(td3);
table.appendChild(tr1);
table1.appendChild(tr2);
li.appendChild(table);
li.appendChild(table1);
ul.appendChild(li);
}
listview.appendChild(ul);
}
Minimal AppLaud App
Coupons Shop
ScreenShot
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
outline: none;
}
html { height: 101%; }
body { font-size: 62.5%; line-height: 1; font-family: Verdana, Arial, Tahoma, sans-serif; }
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; }
ol, ul { list-style: none; }
blockquote, q { quotes: none; }
blockquote:before, blockquote:after, q:before, q:after { content: ; content: none; }
table { border-collapse: collapse; border-spacing: 0; }
img { border: 0; max-width: 100%; }
a { text-decoration: none; }
/** content display **/
#view { display: block; max-width: 800px; padding: 0; margin: 0; }
#container { display: block; margin-top: 55px; }
#container ul { }
#container ul a li {
display: block;
width: 100%;
height: 90px;
border-bottom: 1px solid #b9b9b9;
border-top: 1px solid #f7f7f7;
background: #ebebeb;
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#ffffff) to(#ebebeb));
background-image: -webkit-linear-gradient(top, #ffffff, #ebebeb);
background-image: -moz-linear-gradient(top, #ffffff, #ebebeb);
background-image: -o-linear-gradient(top, #ffffff, #ebebeb);
background-image: linear-gradient(top, #ffffff, #ebebeb);
}
#container ul a { display: block; position: relative; width: 100%; }
#container ul li h2 { font-size: 2.1em; line-height: 1.3em; font-weight: normal; letter-spacing: -0.03em; padding-top: 4px; color: #55678d; }
#container ul li p.desc { color: #555; font-family: Arial, sans-serif; font-size: 1.3em; line-height: 1.3em; white-space: nowrap; overflow: hidden; }
#container ul li .price { position: absolute; bottom: 10px; left: 90px; font-size: 1.2em; font-weight: bold; color: #6ea247; }
#container ul li img.thumbnail {
background: #fff;
display: inline-block;
float: left;
padding: 2px;
margin-top: 6px;
margin-left: 5px;
margin-right: 8px;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}
#container ul a:hover li h2 { color: #7287b1; }
#container ul a:hover li p.desc { color: #757575; }
#container ul a:hover li {
background: #efefef;
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#ffffff) to(#efefef));
background-image: -webkit-linear-gradient(top, #ffffff, #efefef);
background-image: -moz-linear-gradient(top, #ffffff, #efefef);
background-image: -o-linear-gradient(top, #ffffff, #efefef);
background-image: linear-gradient(top, #ffffff, #efefef);
}
/** top header bar **/
header {
display: block;
position: fixed;
top: 0;
z-index: 9999;
height: 55px;
width: 100%;
max-width: 800px;
border-bottom: 1px solid #262422;
background: #195d95;
}
header h2 { font-size: 2.4em; font-family: Tahoma, Arial, sans-serif; font-weight: bold; line-height: 55px; text-align: center; color: #efefef; text-shadow: 1px 1px 0px #000;
animation-duration: 3s;
animation-name: slidein;
}
@keyframes slidein {
from {
margin-left: 100%;
width: 300%
}
to {
margin-left: 0%;
width: 100%;
}
}
/** basic media queries **/
@media only screen and (max-width: 480px) {
#container ul li h2 { font-size: 1.75em; }
#container ul li img.thumbnail { margin-top: 2px; }
}
@media only screen and (max-width: 320px) {
#container ul li p.desc { display: none; }
}
/** clearfix **/
.clearfix:after { content: "."; display: block; clear: both; visibility: hidden; line-height: 0; height: 0; }
.clearfix { display: inline-block; }
html[xmlns] .clearfix { display: block; }
* html .clearfix { height: 1%; }
Subscribe to:
Posts (Atom)
