This is part II of article about Drupal and Android integration.
In the Part I, i wrote about principles of communication and how to implement Drupal module.
In this part of article i'll describe how to implement Android application.
3. Android application
We finished with Drupal configuration and server-side code, and now we create Android client application. It will be an app first asking user to enter username and password and press "Ok" button. If login is succeeded, app show user an activity, where he can enter page title and body, make photo, and post it to the server.
XML-RPC is not supported on Android out-of-box, but there is a good library from Redstone. (http://xmlrpc.sourceforge.net/). Redstone's license is commercial friendly, so you can use this library in your commercial applications for free. I modified it to work it properly on Android. And you can download code with my modifications (link is given in the end of article).
Redstone XML-RPC contains many classes, but to start using it, you need to know a few of them.
XmlRpcClient. acts as XML-RPC client, sending requests to server. It takes url of endpoint to connect to. For example: http://yoursite.com/?q=android.
XmlRpcStruct is XML-RPC named values structure, where each member has it's name and value. Similar to Map. Many XML-RPC method arguments and return values are passed in this structure.
All Drupal conversations will be implemented in DrupalConnect class. This class will contain methods for authentication, logout, post page, delete page and upload photo. For photo uploads, i created http client. It's more lightweight, than standard Android clients, and supports upload progress reporting. You can find it in my source code for Android app. DrupalConnect is made as singlton pattern, because there is only one connection per app, and it must be available from many places.
Define urls. Please, replace URLBASE value with your Drupal website address.
Method start is the same, as previous. Remote method params is structure, that contains only page nid. And return type of remote method is boolean, indicating, whether page is deleted or not.
Now, create login activity. It will contain two EditText controls for login and password, remember check box, used to remember last succesful login data, login and cancel buttons.
In LoginActivity class, first define UI control variables.
Define UI control varibles.
Next, implement "Post" button handler.
It gets page title and body from EditText controls, then shows progress dialog, with "Posting. Please, wait." message. And then, creates AsyncTask for performing call to Drupal. Please, look at onPostExecute method of AsyncTask, it hides progress dialog and checks for post result. If post if succeeded, but there is also photo made by an user, it calls uploadPhoto method. Code for this method is given below.
First, it show progress dialog with "Uploading photo" message, and starts AsyncTask for the actual upload. It create PhotoParams structure with photo file, file name, and page node identifier (the page to which a photo be attached). Calls DrupalConnect's uploadPhoto method, passing it PhotoParams and http progress listener arguments. Listener reports http upload progress. It's sendProgress method calls AsyncTask's publishProgress to update progress dialog's progress. The actual progress dialog update is performed in onProgressUpdate method of our async task. When upload is done, onPostExecute hides progress dialog, and checks for result. If all is ok, it show "Post and upload are succeeded." message. But, if there is an error, we must delete page as it's already created on Drupal's side, but our transaction is failed. To perform this, call method deletePage of PostActivity. The code for deletePage is given below.
And again, we create the AsyncTask to perform Drupal remote call. We pass page nid (stored from last postPage call) to DrupalConnect's deletePage method. And finally, we need to implement handlers for "Exit" button. It will perform logout and close PostActivity.
And again, conversation with DrupalConnect is made in AsyncTask.
Summary.
You can see, how easy it's to connect Drupal and Android using XML-RPC. I shown only how to create and delete pages and upload photos, it's also possible to manipulate other Drupal objects (comments, files, users, etc), register new users and more. This approach is applicable to other web CMSes, that supports XML-RPC, and to other mobile platforms.
Please, send me your comments and suggestions.
About author.
I'm software developer with more than 12 years of programming experience. My primary interests are: systems architecture and design, web, network, mobile programming, Unix systems (Linux/FreeBSD), system programming and reverse engineering. I like all new cutting edge technologies, and was very excited by Android platform. Currently, i'm working on several projects, related to web, mobile and desktop integration.
You can download source code for this article here: https://github.com/BItGriff/AndroidDrupal/archive/master.zip
In the Part I, i wrote about principles of communication and how to implement Drupal module.
In this part of article i'll describe how to implement Android application.
3. Android application
We finished with Drupal configuration and server-side code, and now we create Android client application. It will be an app first asking user to enter username and password and press "Ok" button. If login is succeeded, app show user an activity, where he can enter page title and body, make photo, and post it to the server.
XML-RPC is not supported on Android out-of-box, but there is a good library from Redstone. (http://xmlrpc.sourceforge.net/). Redstone's license is commercial friendly, so you can use this library in your commercial applications for free. I modified it to work it properly on Android. And you can download code with my modifications (link is given in the end of article).
Redstone XML-RPC contains many classes, but to start using it, you need to know a few of them.
XmlRpcClient. acts as XML-RPC client, sending requests to server. It takes url of endpoint to connect to. For example: http://yoursite.com/?q=android.
XmlRpcStruct is XML-RPC named values structure, where each member has it's name and value. Similar to Map. Many XML-RPC method arguments and return values are passed in this structure.
All Drupal conversations will be implemented in DrupalConnect class. This class will contain methods for authentication, logout, post page, delete page and upload photo. For photo uploads, i created http client. It's more lightweight, than standard Android clients, and supports upload progress reporting. You can find it in my source code for Android app. DrupalConnect is made as singlton pattern, because there is only one connection per app, and it must be available from many places.
Define urls. Please, replace URLBASE value with your Drupal website address.
/** Base url of Drupal installation */ final static private String URLBASE = "http://192.168.1.9/drupal"; /** XML-RPC url */ final static private String XMLRPC = URLBASE + "/?q=androidrpc"; /** Photoupload url */ final static private String PHOTOUPLOAD = URLBASE + "/?q=photoupload";
Now, implement login method
/** * Perform authentication. * @param username user name * @param password password * @throws IOException * @throws XmlRpcException * @throws XmlRpcFault */ public void login(String username, String password) throws IOException, XmlRpcException, XmlRpcFault { if (isAuthenticated()) logout(); XmlRpcClient xmlrpc = new XmlRpcClient(XMLRPC, false); XmlRpcStruct res = (XmlRpcStruct) xmlrpc.invoke("user.login", new Object[] { username, password }); sessid = res.getString("sessid"); session_name = res.getString("session_name"); }
First, we check if already authenticated, and if so, perform logout.
Next, create XmlRpcClient. First argument is endpoint url, second - whether to stream messages. Message streaming not compatible with all server-side implementations, so set it to false.
The actual remote method invocation performed by xmlrpc.invoke. First argument is a method name, and second is array of arguments - if this case, it's username and password. invoke method can have many return types. In the case of user.login method, it will be XmlRpcStruct structure containing info about session and logged in user (email, uid, etc).
Drupal session defined by the two members of returned structure: sessid and session_name. Save them to be used in all subsequent remote calls, to identify our session.
As we defined login method, we also must define logout.
/** * Close session. * @throws MalformedURLException * @throws XmlRpcException * @throws XmlRpcFault */ public void logout() throws MalformedURLException, XmlRpcException, XmlRpcFault { if (!isAuthenticated()) return ; try { // create xml-rpc client XmlRpcClient xmlrpc = new XmlRpcClient(XMLRPC, false); // set session cookie xmlrpc.setRequestProperty("Cookie", getSessionCookieString()); // remote call xmlrpc.invoke("user.logout", new Object[] { }); } catch (Exception ex) { ex.printStackTrace(); } sessid = null; session_name = null; }
First, check if we are authenticated. If no, just return. Next, create XmlRpcClient. Please, take a look at setRequestProperty method call. This method sets additional http header that will be sent with XML-RPC request. We set Cookie identifying Drupal session.
We created login and logout methods. And now we make postPage method.
/** * Posts page. * @param title page title * @param body page body * @return page node identifier * @throws IOException * @throws XmlRpcException * @throws XmlRpcFault */ @SuppressWarnings("unchecked") public int postPage(String title, String body) throws IOException, XmlRpcException, XmlRpcFault { // check if user is authenticated if (!isAuthenticated()) { throw new IllegalStateException("Session is not open."); } // create xml-rpc client XmlRpcClient xmlrpc = new XmlRpcClient(XMLRPC, false); // set session cookie xmlrpc.setRequestProperty("Cookie", getSessionCookieString()); // set page values XmlRpcStruct params = new XmlRpcStruct(); params.put("type", "page"); params.put("title", title); params.put("body", body); // remote call XmlRpcStruct res = (XmlRpcStruct) xmlrpc.invoke("node.create", new Object[] { params }); // get page nid and return it return Integer.parseInt(res.get("nid").toString()); }
And again, first check if user is authenticated. Then create XML-RPC client and setup session cookie. Next, create structure defining node params. type = "page", title and body. And perform the remote call. Remote call returns structure, where we need "nid" member - it's page node identifier, that will be used, for example, to remove page or update it.
Create deletePage method.
/** * Delete page. * @param nid page node identifier * @throws IOException * @throws XmlRpcException * @throws XmlRpcFault */ public boolean deletePage(int nid) throws IOException, XmlRpcException, XmlRpcFault { // check if user is authenticated if (!isAuthenticated()) { throw new IllegalStateException("Session is not open."); } // create xml-rpc client XmlRpcClient xmlrpc = new XmlRpcClient(XMLRPC, false); // set session cookie xmlrpc.setRequestProperty("Cookie", getSessionCookieString()); // page params: nid XmlRpcStruct params = new XmlRpcStruct(); params.put("nid", ""+nid); // node.delete return boolean indicating, whether node is removed or not return (Boolean) xmlrpc.invoke("node.delete", new Object[] { params }); }
Method start is the same, as previous. Remote method params is structure, that contains only page nid. And return type of remote method is boolean, indicating, whether page is deleted or not.
Now, create uploadPhoto method, for photo uploads.
/** * Perform photo upload. * @param photoParams photo params (such as file, file name, page node identifier) * @param listener listener to receive send progress notifications * @throws IOException if an error is occurred */ public void uploadPhoto(PhotoParams params, HttpProgressListener listener) { // check if user is authenticated if (!isAuthenticated()) { throw new IllegalStateException("Session is not open."); } HttpMultipartClient httpClient = new HttpMultipartClient(PHOTOUPLOAD, listener); httpClient.addHeader("Cookie", getSessionCookieString()); httpClient.addField("form_id", "photoupload_upload_file"); httpClient.addField("op", "Upload"); httpClient.addField("nid", ""+params.nid); httpClient.addFile("files[image]", "image/jpeg", params.fileName, params.file); httpClient.post(); }
It's all done with DrupalConnect class.
In LoginActivity class, first define UI control variables.
// UI controls private EditText editUsername; private EditText editPassword; private CheckBox checkRemember; private Button buttonOk; private Button buttonCancel;
In onCreate method, get UI controls, setup button handlers.
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); // get UI controls editUsername = (EditText) findViewById(R.id.editUsername); editPassword = (EditText) findViewById(R.id.editPassword); checkRemember = (CheckBox) findViewById(R.id.checkRemember); buttonOk = (Button) findViewById(R.id.buttonOk); buttonOk.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { onButtonOk(); } }); buttonCancel = (Button) findViewById(R.id.buttonCancel); buttonCancel.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { onButtonCancel(); } }); PrefsHelper.setup(this, "AndroidDrupal"); loadAuthData(); }
Now, define "Ok" button handler.
/** * Called to button "ok" click. */ public void onButtonOk() { final String username = editUsername.getText().toString(); final String password = editPassword.getText().toString(); // string buffer for errors StringBuilder errors = null; // check user name if (username.trim().length() == 0 || !username.matches("\\w+")) { if (errors == null) errors = new StringBuilder(); errors.append("Invalid user name\n"); } // check password if (password.trim().length() == 0 || !password.matches("\\w+")) { if (errors == null) errors = new StringBuilder(); errors.append("Invalid password\n"); } // if (errors != null) { GUIHelper.showError(this, errors.toString()); return ; } // show login progress dialog final ProgressDialog dlg = ProgressDialog.show(this, "Logging in", "Logging in. Please wait.", true, true); // create an async task to perform login (new AsyncTask() { @Override protected String doInBackground(Void... params) { try { DrupalConnect.getInstance().login(username, password); return "OK"; } catch (Exception ex) { return ex.getMessage(); } } @Override protected void onPostExecute(String result) { dlg.dismiss(); if (result.equals("OK")) { saveAuthData(); // switch to MainActivity Intent intent = new Intent(LoginActivity.this, PostActivity.class); startActivity(intent); finish(); } else { GUIHelper.showError(LoginActivity.this, "Login is failed. " + result); } } }).execute(); }
First, it checks username and password, and if it's error - show error message and return. Next, create ProgressDialog, showing "Logging in. Please wait.". And then, create AsyncTask to perform login. In it's doInBackground we call our singleton DrupalConnect class method login. In onPostExecute method (called after doInBackground is complete), we check the result. If all is ok, switch to the next activity. If there is an error, show the message describing what's wrong.
We created our first activity for user login. And how create the main application activity, call it PostActivity. It will be simple activity with two EditText controls for title and body, and three buttons: make photo, post and exit. User will enter title and body, and if he wants to also attach a photo, he clicks "Make photo" button. When all done, he clicks "Post" button, to make post and upload photo (if he made it).
We created our first activity for user login. And how create the main application activity, call it PostActivity. It will be simple activity with two EditText controls for title and body, and three buttons: make photo, post and exit. User will enter title and body, and if he wants to also attach a photo, he clicks "Make photo" button. When all done, he clicks "Post" button, to make post and upload photo (if he made it).
Define UI control varibles.
// UI controls
private EditText editTitle;
private EditText editBody;
private Button buttonMakePhoto;
private Button buttonPost;
private Button buttonExit;
Get UI controls and setup button handlers in onCreate method.
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_post); // get UI controls editTitle = (EditText) findViewById(R.id.editTitle); editBody = (EditText) findViewById(R.id.editBody); buttonMakePhoto = (Button) findViewById(R.id.buttonMakePhoto); buttonMakePhoto.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { makePhoto(); } }); buttonPost = (Button) findViewById(R.id.buttonPost); buttonPost.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { postPage(); } }); buttonExit = (Button) findViewById(R.id.buttonExit); buttonExit.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { exit(); } }); }
Create "Make photo" button handler.
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_post); // get UI controls editTitle = (EditText) findViewById(R.id.editTitle); editBody = (EditText) findViewById(R.id.editBody); buttonMakePhoto = (Button) findViewById(R.id.buttonMakePhoto); buttonMakePhoto.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { makePhoto(); } }); buttonPost = (Button) findViewById(R.id.buttonPost); buttonPost.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { postPage(); } }); buttonExit = (Button) findViewById(R.id.buttonExit); buttonExit.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { exit(); } }); }
It calls standard Android's image capture activity to capture image from camera. Now, we need to override onActivityResult in PostActivity to get capture result. It will be called after camera activity is closed.
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_post); // get UI controls editTitle = (EditText) findViewById(R.id.editTitle); editBody = (EditText) findViewById(R.id.editBody); buttonMakePhoto = (Button) findViewById(R.id.buttonMakePhoto); buttonMakePhoto.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { makePhoto(); } }); buttonPost = (Button) findViewById(R.id.buttonPost); buttonPost.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { postPage(); } }); buttonExit = (Button) findViewById(R.id.buttonExit); buttonExit.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { exit(); } }); }
Next, implement "Post" button handler.
private void postPage() { // check if posting is in progress if (isPostInProgress) { return ; } isPostInProgress = true; // get page title and body final String title = editTitle.getText().toString(); final String body = editBody.getText().toString(); // show progress dialog final ProgressDialog progressDialog = ProgressDialog.show(this, "Posting", "Posting. Please, wait.", true, false); // start async task for posting to Drupal (new AsyncTask() { Exception e; @Override protected Boolean doInBackground(Void... params) { try { nid = DrupalConnect.getInstance().postPage(title, body); return true; } catch (Exception e) { this.e = e; return false; } } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); progressDialog.dismiss(); if (result) { // if user made photo - upload it // if not - report that post succeeded if (CameraHelper.photoFile != null) { uploadPhoto(); } else { GUIHelper.showMessage(PostActivity.this, "Post succeeded.", "Message"); isPostInProgress = false; } } else { GUIHelper.showError(PostActivity.this, "Post is failed. "+e.getMessage()); isPostInProgress = false; } } }).execute(); }
It gets page title and body from EditText controls, then shows progress dialog, with "Posting. Please, wait." message. And then, creates AsyncTask for performing call to Drupal. Please, look at onPostExecute method of AsyncTask, it hides progress dialog and checks for post result. If post if succeeded, but there is also photo made by an user, it calls uploadPhoto method. Code for this method is given below.
private void uploadPhoto() { // create progress dialog final ProgressDialog progressDialog = new ProgressDialog(this); progressDialog.setTitle("Uploading photo"); progressDialog.setMessage("Uploading photo"); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setIndeterminate(false); progressDialog.setCancelable(false); progressDialog.show(); // create async task to upload photo (new AsyncTask() { Exception e; @Override protected Boolean doInBackground(Void... params) { PhotoParams photoParams = new PhotoParams(); photoParams.nid = nid; photoParams.file = CameraHelper.photoFile; photoParams.fileName = CameraHelper.photoFile.getName(); DrupalConnect.getInstance().uploadPhoto(photoParams, new HttpProgressListener() { @Override public void sendStarted(int total) { publishProgress(0, total); } @Override public void sendProgress(int uploaded, int total){ publishProgress(uploaded, total); }
@Override public void sendError(Exception ex) { e = ex; } @Override public void sendDone() { } }); return null; }
@Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); progressDialog.dismiss(); // check if exception is occurred during upload if (e == null) { // delete photo file // it must be deleted when upload is succeeded deletePhoto(); GUIHelper.showError(PostActivity.this, "Post and upload are succeeded."); } else { GUIHelper.showError(PostActivity.this, "Upload is failed. "+e.getMessage()); // delete page deletePage(); } isPostInProgress = false; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); int sent = values[0]; int total = values[1]; // if this is the first call, set progress dialog max value if (sent == 0) { progressDialog.setMax(total); } progressDialog.setProgress(values[0]); } }).execute(); }
First, it show progress dialog with "Uploading photo" message, and starts AsyncTask for the actual upload. It create PhotoParams structure with photo file, file name, and page node identifier (the page to which a photo be attached). Calls DrupalConnect's uploadPhoto method, passing it PhotoParams and http progress listener arguments. Listener reports http upload progress. It's sendProgress method calls AsyncTask's publishProgress to update progress dialog's progress. The actual progress dialog update is performed in onProgressUpdate method of our async task. When upload is done, onPostExecute hides progress dialog, and checks for result. If all is ok, it show "Post and upload are succeeded." message. But, if there is an error, we must delete page as it's already created on Drupal's side, but our transaction is failed. To perform this, call method deletePage of PostActivity. The code for deletePage is given below.
private void deletePage() { // check if there is page if (nid == 0) { return ; }
(new AsyncTask() { @Override protected Boolean doInBackground(Void... params) { try { DrupalConnect.getInstance().deletePage(nid); nid = 0; } catch (Exception e) { e.printStackTrace(); } return null; } }).execute(); }
And again, we create the AsyncTask to perform Drupal remote call. We pass page nid (stored from last postPage call) to DrupalConnect's deletePage method. And finally, we need to implement handlers for "Exit" button. It will perform logout and close PostActivity.
private void exit() { (new AsyncTask() { @Override protected Boolean doInBackground(Void... params) { try { DrupalConnect.getInstance().logout(); } catch (Exception e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); PostActivity.this.finish(); } }).execute(); }
And again, conversation with DrupalConnect is made in AsyncTask.
Summary.
You can see, how easy it's to connect Drupal and Android using XML-RPC. I shown only how to create and delete pages and upload photos, it's also possible to manipulate other Drupal objects (comments, files, users, etc), register new users and more. This approach is applicable to other web CMSes, that supports XML-RPC, and to other mobile platforms.
Please, send me your comments and suggestions.
About author.
I'm software developer with more than 12 years of programming experience. My primary interests are: systems architecture and design, web, network, mobile programming, Unix systems (Linux/FreeBSD), system programming and reverse engineering. I like all new cutting edge technologies, and was very excited by Android platform. Currently, i'm working on several projects, related to web, mobile and desktop integration.
You can download source code for this article here: https://github.com/BItGriff/AndroidDrupal/archive/master.zip
Hello,
ОтветитьУдалитьthanks for this nice turtorial.
I have a simple drupal site running on a virtual machine and I tried this example.
Unfortunately, when I am trying to run it, after pressing the ok button I get the
above exception:
FATAL EXCEPTION: main
05-03 13:53:22.217: E/AndroidRuntime(541): java.lang.NullPointerException
05-03 13:53:22.217: E/AndroidRuntime(541): at com.bitgriff.androiddrupal.LoginActivity$3.onPostExecute(LoginActivity.java:124)
05-03 13:53:22.217: E/AndroidRuntime(541): at com.bitgriff.androiddrupal.LoginActivity$3.onPostExecute(LoginActivity.java:1)
05-03 13:53:22.217: E/AndroidRuntime(541): at android.os.AsyncTask.finish(AsyncTask.java:602)
05-03 13:53:22.217: E/AndroidRuntime(541): at android.os.AsyncTask.access$600(AsyncTask.java:156)
05-03 13:53:22.217: E/AndroidRuntime(541): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:615)
05-03 13:53:22.217: E/AndroidRuntime(541): at android.os.Handler.dispatchMessage(Handler.java:99)
05-03 13:53:22.217: E/AndroidRuntime(541): at android.os.Looper.loop(Looper.java:137)
05-03 13:53:22.217: E/AndroidRuntime(541): at android.app.ActivityThread.main(ActivityThread.java:4340)
05-03 13:53:22.217: E/AndroidRuntime(541): at java.lang.reflect.Method.invokeNative(Native Method)
05-03 13:53:22.217: E/AndroidRuntime(541): at java.lang.reflect.Method.invoke(Method.java:511)
05-03 13:53:22.217: E/AndroidRuntime(541): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
05-03 13:53:22.217: E/AndroidRuntime(541): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
05-03 13:53:22.217: E/AndroidRuntime(541): at dalvik.system.NativeStart.main(Native Method)
Do you have any idea about what's going on?
Thanks in advance
Did you changed the code?
УдалитьIf no, try to find 'if (result.equals("OK")) {' in LoginActivity.java, and replace it to
'if (result != null && result.equals("OK")) {`
You're right, it returns null. But I downloaded all the needed modules. Also, when I make a "post call" from a google chrome plugin it returns ok, and the only response I get is "XML-RPC server accepts POST requests only." ...
ОтветитьУдалитьThat's strange. XmlRpc use POST requests, and XmlRpc lib, used in sample use POSTs.
УдалитьYes I know..., are you aware of any module that I could add to resolve that problem?
УдалитьI think, no module need to be added. For xml-rpc you require only drupal core and services module. Maybe it's a problem of particular drupal and services module version. What version are you using?
УдалитьI'm using drupal7 and 7.x-3.3 for the services module version..
УдалитьI tested on Drupal 7 installation. XmlRpc lib cannot make requests other than POST. Do you have proxies or etc?
УдалитьHello again, at last I solved the problem. I had a mistake on URL. Thank you for your help. I'd like to ask you something else. Is there a way to implement a "get method" using XmlRpc server? If not, do you know how to implement it using the Rest Server? Thanks in advance
ОтветитьУдалитьXmlRpc support only POST method. Not sure about REST.
УдалитьI think Rest support GET method. Unfortunately, I cannot find any examples using Rest with java... Would you please tell me, if it is possible to change some code on this project to use it with Rest? Would it be a difficult procedure?
УдалитьYes, it's possible.
УдалитьYou need to remove xmlrpc lib code, and add REST lib to the project.
All XmlRpc communication is in the DrupalConnect class. You need to replace XmlRpc calls in it to REST calls.
So, I only need to change some things on DrupalConnect? Or change the other packages that are referring to Xmlrpc?
ОтветитьУдалитьAll communication is contained in DrupalConnect.
УдалитьJust remove packages with names like "redstone.xmlrpc", and replace XmlRpc code in DrupalConnect with REST calls.
Dear reader,
ОтветитьУдалитьi implemented your drupal/android app and was going really well up to the part where the photo needed to be uploaded. Android gave exception: Post is failed. Node type page does not exist.
Can you direct me in the right way to solve this problem? Thank you so much.
Regards,
Stephan
Этот комментарий был удален автором.
Удалить"Node type page doesn't exist". means that there in no page content type in Drupal.
УдалитьPlease, check your Drupal configuration, "Content types" page.
Best regards.
Hello, thank you for your time. But I created a View for images, through a self made content type. Isn't that enough?
ОтветитьУдалитьI'm a newbe with drupal and i cannot seem to create the right content type page.
Thank you again for your time.
Stephan
Try to change node type in DrupalConnect class to yours'.
УдалитьBest regards.
Thank you for your time, again. But now I'm through to uploading the photo, but i get a 500 internal server error. It has something to do with the attached image because if i leave the image out and just post the title/body it works fine. Please help me out this last time. Thank you.
ОтветитьУдалитьLook at DrupalConnect's uploadPhoto method. And PHOTOUPLOAD field.
УдалитьIs photoupload Drupal module installed?
I think it is because I use drupal 7 that some functions are no longer existing from drupal 6 like file_set_status().
ОтветитьУдалитьI'm trying to alter the code in PHP to work with drupal 7.
Yes, it's can be caused by not existing functions.
УдалитьThis is way above my head. Did someone upgrade the php script to drupal 7??
ОтветитьУдалитьЭтот комментарий был удален автором.
ОтветитьУдалитьЭтот комментарий был удален автором.
ОтветитьУдалитьi am getting a similar error 500 when i try to upload an image. Without image the upload works. The module is enabled and its drupal 6. Kindly guide on what am i still missing. In the log entries i see a page getting created but gets deleted immediately.
ОтветитьУдалитьPage deleted because if operation fail (create node and upload image), all it's steps are rolled back.
УдалитьWhy is the node creation/ upload image operation failing? is this a permission issue? It fails only when an image is there else succeeds. Permission for upload photo, node create etc is all provided. The module is enabled. Size allowed is >5mb while image is <2mb. What am i missing? & how to make it work?
ОтветитьУдалитьNode creation is made through xml-rpc call, image upload by making POST to form created/handled by photoupload module.
УдалитьPlease, check your drupal logs.
Hi , I am facing a problem with services 7.x-3.5 module. The app give gives" X-CSRF-Token validation failed " when I try to post. I also tried installing the module services 7.x-3.3 as suggested in https://groups.drupal.org/node/358308#comment-983068. After that the image gets uploaded but it gives an error saying "Upload is failed . Invalid Response. HTTP/1.1 200 OK" .Please can you help with this problem ?
ОтветитьУдалитьThis information is impressive; I am inspired with your post writing style & how continuously you describe this topic. After reading your post, thanks for taking the time to discuss this, I feel happy about it and I love learning more about this topic.Android Training in chennai | Best Android Training in chennai|
ОтветитьУдалитьGenyatra provides train tickets, flight tickets, senior citizen yatra , foreign exchange, visa services to its Clients across World.
ОтветитьУдалитьFlight tkt, teerthyatra, foreign exchange rail ticket
Big Truck Tow: Heavy Duty towing service san jose
ОтветитьУдалитьWe're rated the most reliable heavy duty towing san jose service & roadside assistance in San Jose!
Call us now! We're ready to help you NOW!
Since 1999, tow truck san jose has provided quality services to clients by providing them
with the professional care they deserve. We are a professional and affordable Commercial
Towing Company. BIG TRUCK TOW provides a variety of services, look below for the list of
services we offer. Get in touch today to learn more about our heavy duty towing
Click here to Find tow truck near me
crowdsourcehttp://www.incruiter.com recruitment agency.
ОтветитьУдалитьWe ’incruiter’ provide a uniquerecruitment agencies platform to various committed professionals
placement consultancyacross the globe to use their skills and expertise to join as a recruiter and
interviewer to empower the industry with talented human resources.Searching for the right candidate is never easy.
job consultancy We use crowdsource recruitment to find right talent pool at much faster pace.
Our candidate search follows application of a rigorous methodology, and a comprehensive screening to find an individual
whorecruitment consultants is not only skilled but is also the right culture fit for your organization.
Our interviewers are best in the industry,staffing agencies being experts from various verticals to judge right
candidate for the job. They interview candidates taking into account primarily defined job specification of our clients and targeting
them for needs of the organization.Thinking about payment?placement agencies Don’t worry, you pay when you hire.
Whether you are a startup or an established enterprise, join our 10x faster recruitment process that reduces your hiring process by 50% and give you
manpower consultancyefficient results.
check our website:http://www.incruiter.com.
The Asigo System Review- Read It Before You Buy - Kingss Lyn
ОтветитьУдалитьThe Asigo system review explains how Chris munch asigo system review has jotted down a step by step
training to help internet marketers get fast results His.Staregies Work!
For More Information Visit https://kingsslyn.com/the-asigo-system-review/ Here .
Talk with Strangerstalk to strangers in Online Free Chat rooms where during a safe environment.
ОтветитьУдалитьFrom friendships to relationships.omegle teen Talk With Stranger is that the best online chatting site.
Its the simplest alternative to airg chat, Badoo , omegle & mocospace. If you're keen on speaking
with people on the web ,chat random or want to seek out omegle girls, do free texting or sexting, make new friends.
you'll find your omegle lady here. Please note this is often not a sexting site so you can't do sexting
online. this is often a familychatous friendly chat site. we've voice chat if you would like to try to to phone
chat online. Our most viral is that the 1-1 one on one random chat.talkwithstranger No check in on login needed.
we've teengers also asanonymous chat older people that want to satisfy new people. Online random chat is that the best
chatrandom alternative.
Nice intro good explanation thanks for sharing. Enrgtech Electronic Limited
ОтветитьУдалитьNice & Informative Blog !
ОтветитьУдалитьOur team at QuickBooks Technical Support Phone Number 1-877-751-0742 makes sure to provide you with the best technical services for QuickBooks in less time.
Hey! Mind-blowing blog. Keep writing such beautiful blogs. In case you are struggling with issues on QuickBooks software, dial QuickBooks Support Phone Number (877)603-0806. The team, on the other end, will assist you with the best technical services.
ОтветитьУдалитьNice & Informative Blog !
ОтветитьУдалитьA prestigious accounting software, QuickBooks, has been designed to make the -flow of accounting painless and hassle-free. However, this software is also prone to technical issues like QuickBooks Error 1304 dial 1-855-977-7463.
Nice Blog !
ОтветитьУдалитьAre you getting QuickBooks Error 8007 while working on QuickBooks software. You are not alone as many of the clientele have complained about this error.
Keep up the good work; I read few posts on this website, including I consider that your blog is fascinating and has sets of the fantastic piece of information. Thanks for your valuable effortsFor QuickBooks Technical support, visit:Quickbooks Customer Service Number
ОтветитьУдалитьGood Work, Nice blog with helpful information, if you face any kind of trouble using QuickBooks, contact immediately:QuickBooks Support and get resolved with your issue.
ОтветитьУдалитьHey! Well-written blog. It is the best thing that I have read on the internet today. Moreover, if you are looking for the solution of QuickBooks Customer Service, visit at QuickBooks Customer Service Number to get your issues resolved quickly.
ОтветитьУдалитьHey! Nice Blog, I have been using QuickBooks for a long time. One day, I encountered QuickBooks Customer Service in my software, then I called QuickBooks Customer Service Number. They resolved my error in the least possible time.
ОтветитьУдалитьAmazing Artcle !!QuickBooks Error 6000 308 most common error that can you resoved by QuickBooks Expert at
ОтветитьУдалитьQuickbooks Phone Number877) 693-1117
Hii!!
ОтветитьУдалитьGood content.wonderful blog. If you are searching for Quickbooks Customer Serviceyou can reach us at.+1 888-210-4052,PA.