Background:
I am using Firebase for my Android App Development This app require every user upload an object from their phone to the bucket/ Firebase Storage once a day. So, I want to make the process of "object upload" as a background service with JobSchedulerAPI.
I have copied source code from Firebase and a youtube video related to Job Scheduler. But when I clicked the button, the app stopped immediately.
MainActivity.Java
package com.scheduleupload;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
final ComponentName mComponentName = new ComponentName(this, Scheduler.class);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
JobInfo info = new JobInfo.Builder(123, mComponentName)
.setPeriodic(15 * 60 * 1000)
.build();
JobScheduler scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
int resultCode = scheduler.schedule(info);
if (resultCode == JobScheduler.RESULT_SUCCESS) {
Log.d(TAG, "Job scheduled");
} else {
Log.d(TAG, "Job scheduling failed");
}
}
});
}
}
Scheduler.Java
package com.scheduleupload;
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.net.Uri;
import android.util.Log;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.UploadTask;
public class Scheduler extends JobService {
private static final String TAG = "ExampleJobService";
private boolean jobCancelled =false;
private StorageReference mStorage;
mStorage = FirebaseStorage.getInstance().getReference();
String myUri = "content://com.google.android.apps.docs.storage/document/acc%3D1%3Bdoc%3D693";
final Uri uri = Uri.parse(myUri);
StorageReference filepath = mStorage.child("Photos").child(uri.getLastPathSegment());
#Override
public boolean onStartJob(JobParameters params) {
Log.d(TAG, "Job Started");
doBackgroundWork(params);
return true;
}
private void doBackgroundWork(JobParameters params) {
new Thread(new Runnable() {
#Override
public void run() {
filepath.putFile(uri);
}
}).start();
}
#Override
public boolean onStopJob(JobParameters params) {
return true;
}
}
Thx a lot for spending such a long while to read my question
crash log:
05-07 21:53:52.775 6261-6261/com.scheduleupload E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.scheduleupload, PID: 6261
java.lang.IllegalArgumentException: No such service ComponentInfo{com.scheduleupload/com.scheduleupload.Scheduler}
at android.os.Parcel.readException(Parcel.java:2008)
at android.os.Parcel.readException(Parcel.java:1950)
at android.app.job.IJobScheduler$Stub$Proxy.schedule(IJobScheduler.java:180)
at android.app.JobSchedulerImpl.schedule(JobSchedulerImpl.java:44)
at com.scheduleupload.MainActivity$1.onClick(MainActivity.java:35)
at android.view.View.performClick(View.java:6294)
at android.view.View$PerformClick.run(View.java:24770)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Have found solution, it is because the Scheduler can't access to some of the storage. Simply change to file location to somewhere it is accessible by Job Scheduler can solve the problem
Related
I'm creating an app in which there are three tab activity.In tab Three i have a textview name as login text whenever user click on this text a new activity should be opened but app crashes when we click on this.
I have done many research to resolve this problem but i'm unable to resolve at last i'm here for the solution of my problem Please help.
Thanks in advance.
This is my loginActivity.
import android.app.ProgressDialog;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
public class loginActivity extends AppCompatActivity implements View.OnClickListener {
private EditText email_Id;
private EditText password;
private TextView sign_Up;
private Button sign_In;
private ProgressDialog progressDialog;
private FirebaseAuth firebaseAuth;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
firebaseAuth=FirebaseAuth.getInstance();
// if(firebaseAuth.getCurrentUser()!=null){
// directly start user profile activity
// finish();
// startActivity(new Intent(this,userProfileActivity.class));
//}
progressDialog=new ProgressDialog(this);
email_Id=(EditText)findViewById(R.id.email_id);
password=(EditText)findViewById(R.id.password);
sign_In=(Button)findViewById(R.id.sign_In);
sign_Up=(TextView)findViewById(R.id.sign_up);
sign_In.setOnClickListener(this);
sign_Up.setOnClickListener(this);
}
private void user_Login(){
String email=email_Id.getText().toString().trim();
String pass_word=password.getText().toString().trim();
if(TextUtils.isEmpty(email)){
// email is empty
Toast.makeText(this,"please enter email",Toast.LENGTH_SHORT).show();
return;// to stop the function from executation.
}
if(TextUtils.isEmpty(pass_word)){
// email is empty
Toast.makeText(this,"please enter password",Toast.LENGTH_SHORT).show();
return;
}
// here if everything ok the user will be register
progressDialog.setMessage("Registering User,please wait...");
progressDialog.show();
firebaseAuth.signInWithEmailAndPassword(email,pass_word)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
progressDialog.dismiss();
if (task.isSuccessful()){
// start user profile activity
finish();
startActivity(new Intent(getApplicationContext(),userProfileActivity.class));
}
}
});
}
#Override
public void onClick(View view) {
if (view==sign_In){
// start user profile activity
user_Login();
}
if(view==sign_Up){
// go to registeration page
finish();
startActivity(new Intent(this,FragmentThree.class));
}
}
}
this is declaration
This is my login method
The following line in your code throws the exception:
sign_Up.setOnClickListener(this);
The problem is, that sign_Up is null!
You set sign_Up with: sign_Up=(TextView)findViewById(R.id.sign_up);
Make sure, that setContentView(R.layout.activity_login); (activity_login) is the right one. If, try to clean and rebuild your project and try again.
Update: It is possible, that sign_up should be a button? If, you make a wrong cast!
Change the TextView in this line:
sign_Up=(TextView)findViewById(R.id.sign_up);
to Button, like this:
sign_Up=(Button)findViewById(R.id.sign_up);
I'm having a problem with use the FirebaseMessagingService. The FirebaseMessagingService works fine. I receive the messages and the notifications. But I need send the message to Activity opened, and invoke a method in activity.
I tried create a listener, but when receive a message, is created a new instance and the listener be null. I understand that FirebaseMessagingService is instanciated when have a message to receive. So I thought in singleton and listener together, don't work, the listener keep null.
Someone have a idea how I can send a message to activity opened?
I don't think any listeners are needed for this. Once you get message in onMessageReceived(), just broadcast it using LocalBroadcastmanager. and receive that broadcast in your activity.
Below is the code snippet to achieve what you want:
MyFirebaseMessagingService.java
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Intent intent = new Intent(**Action**);
intent.putExtra("Some Payload", message.getBody());
mLocalBroadcastManager.sendBroadcast(intent);
}
MainActivity.java
private LocalBroadcastManager mLocalBroadcastManager;
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
}
};
#Override
protected void onStart() {
super.onStart();
registerBroadcastReceiver();
}
#Override
protected void onStop() {
super.onStop();
unregisterBroadcastReceiver();
}
private void registerBroadcastReceiver() {
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(**Action**);
mLocalBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);
}
private void unregisterBroadcastReceiver() {
mLocalBroadcastManager.unregisterReceiver(mBroadcastReceiver);
}
Be care full though not to exceed limitations of data sizes that can be passed using intents
refer here
https://code.google.com/p/android/issues/detail?id=5878
I understood your question with out any code. Here is pretty much a turn key solution for you that should work. I use this method a lot to pass data between services and activities.
The first thing you need to to is convert the data you want to pass to something that can be passed through an intent.
Strings are easy to work with so convert to string and put in an intent. On the activity side using onCreate and onNewItent you can receive this data no problem. Then convert it back how ever you wish. See code below for an example.
Working with broadcast receivers has the possibilities of giving you data leaks if the receiver is not unRegistered. It will happen if you app crashes and the unRegister is not told to shutdown.
In your FirebaseMessagingService class
import android.os.AsyncTask;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Map;
/**
* Created by acopp
* Date: 12/31/2016.
* Time: 1:41 PM
* You have permission to use this file for any reason that is not for evil doing
*/
public class FBMService extends FirebaseMessagingService {
static String TAG = "FBMService";
static String FBMServiceAction = "FBMService.Action";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
MainActivity.passIntent(this,FBMServiceAction,getString(remoteMessage));
}
String getString(RemoteMessage message){
Map<String, String> messageData = message.getData();
JSONObject j = new JSONObject();
for (String key : messageData.keySet()) {
String value = messageData.get(key);
try {
j.put(key, value);
} catch (JSONException e) {
e.printStackTrace();
}
}
return j.toString();
}
}
Activity Class
//In your activity class
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Created by acopp
* Date: 12/31/2016.
* Time: 1:41 PM
* You have permission to use this file for any reason that is not for evil doing
*/
public class MainActivity extends Activity {
private String TAG = "MainActivity";
//Call this from FBMService to start your activity or if your activity is start to receive a new intent
static void passIntent(Context context, String action, String messageDataString) {
Intent intent = new Intent(context, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("action", action);
intent.putExtra("message", messageDataString);
context.startActivity(intent);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
intentHandler(getIntent());
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d(TAG, "onNewIntent");
intentHandler(intent);
}
//Use an intent handler to manage onNewIntent and onCreate the same way
void intentHandler(Intent intent) {
if (intent.hasExtra("action")) {
String action = intent.getStringExtra("action");
if(action.equals(FBMService.FBMServiceAction)){
if (intent.hasExtra("message")) {
String messageDataString = intent.getStringExtra("message");
new iterEat().execute(messageDataString);
}
}
}
}
//Convert your string to a HashMap in the background off the main thread
class iterEat extends AsyncTask<String,Void,Map<String, String> > {
#Override
protected Map<String, String> doInBackground(String... rm) {
String messageDataString = rm[0];
try{
return fromString(messageDataString);
}catch (NullPointerException e){
return null;
}
}
#Override
protected void onPostExecute(Map<String, String> s) {
//Your data is pooped out here
Map<String, String> messageData = s;//PLOP
}
}
Map<String, String> fromString(String jsonString) throws NullPointerException{
try {
Map<String, String> messageData = new HashMap<>();
JSONObject j = new JSONObject(jsonString);
Iterator<String> i = j.keys();
while(i.hasNext()){
String key = i.next();
String value = j.getString(key);
messageData.put(key,value);
}
return messageData;
} catch (JSONException e) {
throw new NullPointerException("Didn't work");
}
}
}
I'm working with a fragment but its always throwing the error that it cannot start the activity because the fragmentis not attached to the activity,
kindly assist me figure out where I'm messing
Below is my code for the Fragment and Activity:
Fragment
package com.sarham.kabs.fruity;
import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.ListFragment;
import android.support.v7.app.ActionBarDrawerToggle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import adapters.CategoriesListAdapter;
/**
* Created by Kabunyi Wanja on 22/03/2015.
*/
public class CategoriesFragment extends ListFragment {
private ListView categoriesListView;
private String[] categoriesArray = getResources().getStringArray(R.array.drawer_list);
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.categories_fragment, container, false);
categoriesListView = (ListView)v.findViewById(android.R.id.list);
//setCategoriesListAdapter();
//Log.d("ADAPTER: ", "Adapter has been set for listview");
return v;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setCategoriesListAdapter();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
//set adapter to categoriesListView
public void setCategoriesListAdapter(){
categoriesListView.setAdapter(new CategoriesListAdapter(getActivity(), categoriesArray));
}
}
Activity
package com.sarham.kabs.fruity;
import android.content.res.Configuration;
import android.os.PersistableBundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.support.v7.app.ActionBarDrawerToggle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
public class MainActivity extends ActionBarActivity implements AdapterView.OnItemClickListener{
private DrawerLayout drawerLayout;
private ListView listView;
private String[] planets;
private ActionBarDrawerToggle drawerListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
drawerLayout = (DrawerLayout)findViewById(R.id.drawerLayout);
listView = (ListView)findViewById(R.id.drawerListView);
planets = getResources().getStringArray(R.array.planets);
listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, planets));
listView.setOnItemClickListener(this);
drawerListener = new ActionBarDrawerToggle(this, drawerLayout,R.string.drawer_open, R.string.drawer_close){
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
Toast.makeText(MainActivity.this,"Drawer Open", Toast.LENGTH_LONG).show();
}
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
Toast.makeText(MainActivity.this, "Drawer Closed", Toast.LENGTH_LONG).show();
}
};
drawerLayout.setDrawerListener(drawerListener);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
CategoriesFragment categories = new CategoriesFragment();
addFragment(R.id.drawerLayout, categories, "CATEGORIES");
}
#Override
public void onPostCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onPostCreate(savedInstanceState, persistentState);
drawerListener.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
drawerListener.onConfigurationChanged(newConfig);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
if(drawerListener.onOptionsItemSelected(item)){
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(this, planets[position]+" Was selected", Toast.LENGTH_SHORT).show();
selectItem(position);
switch (position){
case 0:
CategoriesFragment categories = new CategoriesFragment();
addFragment(R.id.drawerLayout, categories, "CATEGORIES");
break;
case 1:
Toast.makeText(this, "Settings was selected", Toast.LENGTH_SHORT).show();
break;
case 2:
Toast.makeText(this, "Exit was selected", Toast.LENGTH_SHORT).show();
finish();
break;
default:
}
}
public void selectItem(int position){
listView.setItemChecked(position, true);
setTitle(planets[position]);
}
//set ActionBar title
public void setTitle(String title){
getSupportActionBar().setTitle(title);
}
//call this method to add a fragment
public void addFragment(int containerViewId, Fragment fragment, String tag){
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(containerViewId, fragment, tag);
transaction.commit();
}
}
Below is the LogCat ouput:
Caused by: java.lang.IllegalStateException: Fragment CategoriesFragment{41545e80} not attached to Activity
at android.support.v4.app.Fragment.getResources(Fragment.java:619)
at com.sarham.kabs.fruity.CategoriesFragment.<init>(CategoriesFragment.java:21)
at com.sarham.kabs.fruity.MainActivity.onCreate(MainActivity.java:55)
at android.app.Activity.performCreate(Activity.java:5020)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2148)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2211)
at android.app.ActivityThread.access$600(ActivityThread.java:149)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1300)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:153)
at android.app.ActivityThread.main(ActivityThread.java:5086)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:821)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:584)
at dalvik.system.NativeStart.main(Native Method)
On carefull analysis of the Fragment lifecycle, Its not possible to carry out operations like fetching of string resources using the getResources().getStringArray(...) as I was doing, this has to be done within the method onActivityCreated(...)
I am a student and learning JavaFX since a month.
I am developing a application where I want a service to repeatedly start again after its execution of the task. For this I have come to know that 'ScheduledService' is used.
So can anybody please explain the use of scheduledservice with simple example and also how it differs from the 'Service' in JavaFX. Thanks ;)
EDIT : How can I define that this ScheduledService named DataThread should be restarted every 5 seconds ?
public class DataThread extends ScheduledService<Void>
{
#Override
public Task<Void> createTask() {
return new Task<Void>() {
#Override
public Void call() throws Exception {
for(i=0;i<10;i++)
{
System.out.println(""+i);
}
return null;
}
};
}
}
Considering you have a sound knowledge of Service class. ScheduledService is just a Service with a Scheduling functionality.
From the docs
The ScheduledService is a Service which will automatically restart itself after a successful execution, and under some conditions will restart even in case of failure
So we can say it as,
Service -> Execute One Task
ScheduledService -> Execute Same Task at regular intervals
A very simple example of Scheduled Service is the TimerService, which counts the number of times the Service Task has been called. It is scheduled to call it every 1 second
import java.util.concurrent.atomic.AtomicInteger;
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.concurrent.ScheduledService;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.util.Duration;
public class TimerServiceApp extends Application {
#Override
public void start(Stage stage) throws Exception {
TimerService service = new TimerService();
AtomicInteger count = new AtomicInteger(0);
service.setCount(count.get());
service.setPeriod(Duration.seconds(1));
service.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent t) {
System.out.println("Called : " + t.getSource().getValue()
+ " time(s)");
count.set((int) t.getSource().getValue());
}
});
service.start();
}
public static void main(String[] args) {
launch();
}
private static class TimerService extends ScheduledService<Integer> {
private IntegerProperty count = new SimpleIntegerProperty();
public final void setCount(Integer value) {
count.set(value);
}
public final Integer getCount() {
return count.get();
}
public final IntegerProperty countProperty() {
return count;
}
protected Task<Integer> createTask() {
return new Task<Integer>() {
protected Integer call() {
//Adds 1 to the count
count.set(getCount() + 1);
return getCount();
}
};
}
}
}
I have written a Netty server which sends asynchronous messages. The server is working as expected.
I can telnet to the server with a couple of telnet sessions and the asynchronous messages gets written out.
I have written a Netty Client but the client seems to be event driven and not asynchronous. On the server when the client connects; the server writes back to the client "Welcome" and the messages get handled in the client by the messageReceived event, any asynchronous event does not fire any event within the SimpleChannelHandler.
Question: How do I get the Netty client to pick up asynchronous message/events? At the moment it is event driven.
Just to add, the client is the Netty Telnet client.[http://netty.io/docs/stable/xref/org/jboss/netty/example/telnet/package-summary.html]
The Server Code
//---------Server code---------------
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
public class TestServer {
private final ServerBootstrap clientServerBootstrap;
private EchoServerFactory echoServerFactory;
private Channel appChannel;
public TestServer() {
this.clientServerBootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
this.clientServerBootstrap.setOption("child.tcpNoDelay", true);
}
public static void main(String[] args) {
try {
TestServer test = new TestServer();
test.start();
for(int i = 0; i < 100; i++) {
long time = System.currentTimeMillis()+1000;
String data = "setPhase();d(1,1,2.2342,"+time+");";
System.out.println(data);
test.write(data);
Thread.sleep(1000);
}
} catch(Exception ex) {
ex.printStackTrace();
}
}
public void start() {
echoServerFactory = new EchoServerFactory();
clientServerBootstrap.setPipelineFactory(echoServerFactory);
InetSocketAddress isaApp = new InetSocketAddress("127.0.0.1", 9090);
appChannel = clientServerBootstrap.bind(isaApp);
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
stop();
}
}));
}
public void write(String message) throws Exception {
echoServerFactory.write(message);
}
public void stop() {
clientServerBootstrap.releaseExternalResources();
}
}
//---------------Factory----------------------------
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder;
import org.jboss.netty.handler.codec.frame.Delimiters;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
public class EchoServerFactory implements ChannelPipelineFactory {
EchoServerHandler handler = new EchoServerHandler();
public EchoServerHandler getHandler() {
return handler;
}
public void write(String message) throws Exception {
handler.write(message);
}
public ChannelPipeline getPipeline() throws Exception {
// Create a default pipeline implementation.
ChannelPipeline pipeline = org.jboss.netty.channel.Channels.pipeline();
// Add the text line codec combination first,
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
// and then business logic.
pipeline.addLast("handler", handler);
return pipeline;
}
}
//---------------Handler----------------------------
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ChildChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.channel.WriteCompletionEvent;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;
public class EchoServerHandler extends SimpleChannelHandler {
private static final Logger logger = Logger.getLogger(EchoServerHandler.class.getName());
static final ChannelGroup channels = new DefaultChannelGroup();
public void write(String message) throws Exception {
channels.write(message);
}
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
Channel channel = e.getChannel();
channels.add(channel);
channel.write("Welcome\n\n");
}
#Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
// Unregister the channel from the global channel list
// so the channel does not receive messages anymore.
//channels.remove(e.getChannel());
}
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
// Send back the received message to the remote peer.
System.out.println("------------------------->"+e.getMessage());
Channel ch = e.getChannel();
ChannelFuture f = ch.write(e.getMessage());
/* f.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
Channel ch = future.getChannel();
System.out.println("Completed : "+ch.isOpen());
}
});*/
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
// Close the connection when an exception is raised.
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close();
}
}
The Client Code
//---------------- Client Code -------------------
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jfree.ui.RefineryUtilities;
/**
* Simplistic telnet client.
*/
public class TelnetClient {
private final String host;
private final int port;
public TelnetClient(String host, int port) {
this.host = host;
this.port = port;
}
public void run() throws IOException {
// Configure the client.
ClientBootstrap bootstrap = new ClientBootstrap(
new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
// Configure the pipeline factory.
bootstrap.setPipelineFactory(new TelnetClientPipelineFactory());
bootstrap.setOption("tcpNoDelay", true);
// Start the connection attempt.
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
// Wait until the connection attempt succeeds or fails.
Channel channel = future.awaitUninterruptibly().getChannel();
if (!future.isSuccess()) {
future.getCause().printStackTrace();
bootstrap.releaseExternalResources();
return;
}
// Read commands from the stdin.
ChannelFuture lastWriteFuture = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (;;) {
String line = in.readLine();
if (line == null) {
break;
}
// Sends the received line to the server.
lastWriteFuture = channel.write(line + "\r\n");
// If user typed the 'bye' command, wait until the server closes
// the connection.
if (line.toLowerCase().equals("bye")) {
channel.getCloseFuture().awaitUninterruptibly();
break;
}
}
// Wait until all messages are flushed before closing the channel.
if (lastWriteFuture != null) {
lastWriteFuture.awaitUninterruptibly();
}
// Close the connection. Make sure the close operation ends because
// all I/O operations are asynchronous in Netty.
channel.close().awaitUninterruptibly();
// Shut down all thread pools to exit.
bootstrap.releaseExternalResources();
}
public static void main(String[] args) throws Exception {
try {
// Parse options.
String host = "127.0.0.1";
int port = 9090;
new TelnetClient(host, port).run();
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
//---------------- Client Factory -------------------
import static org.jboss.netty.channel.Channels.*;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder;
import org.jboss.netty.handler.codec.frame.Delimiters;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
/**
* Creates a newly configured {#link ChannelPipeline} for a new channel.
*/
public class TelnetClientPipelineFactory implements ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception {
// Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline();
// Add the text line codec combination first,
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(1118192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
// and then business logic.
pipeline.addLast("handler", new TelnetClientHandler2());
return pipeline;
}
}
//----------------- Client handler -------------------
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ChildChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.channel.WriteCompletionEvent;
/**
* Handles a client-side channel.
*/
public class TelnetClientHandler extends SimpleChannelHandler {
private static final Logger logger = Logger.getLogger(TelnetClientHandler.class.getName());
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
System.out.println("messageReceived");
String message = (String) e.getMessage();
parseMessage(message);
}
private void parseMessage(String message) {
try {
System.out.println("Messatge --> "+message);
} catch (Exception ex) {
ex.printStackTrace();
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
System.out.println(e.getCause());
logger.log(Level.WARNING,"Unexpected exception from downstream.", e.getCause());
e.getChannel().close();
}
}
Since you are using delimiter based frame decoder in the Netty Client App, it expects the delimiter at end of each message, but it looks like the server is not sending message with delimiter.
String data = "setPhase();d(1,1,2.2342,"+time+");";
System.out.println(data);
test.write(data);
after above messages are sent, frame decoder is keep waiting even after it received many messages. It works in telnet because, telnet session expects one character at a time. You have done it correctly only for the first message.
channel.write("Welcome\n\n");