I am new to Spring batch. I need to achieve the following:
Step 1: Copy a file from remote location to local directory.
Step 2: Process each line of the file.
Step 3: Store the processed line into a database.
I am sure about the last two steps, but how can I achieve the first step?
Thanks for your help.
you can write a tasklet to achieve this this tasklet would be in separate step
<step id="movingFile" next="step2">
<tasklet ref="voterImportFileMovingTasklet" />
<listeners>
<listener ref="stepLevelListener" />
</listeners>
</step>
<step id="step2" >
<chunk reader="FileReader" processor="ItemProcessor" writer="ItemWriter" commit-interval="300"
skip-limit="1000">
<skippable-exception-classes>
<include class="java.lang.Exception" />
</skippable-exception-classes>
<listeners>
<listener ref="voterImportListener" />
</listeners>
</chunk>
</step>
Tasklet will be
public class FileMovingTasklet implements Tasklet, InitializingBean {
private Resource sourceDirectory;
private Resource targetDirectory;
private static final Log LOG = LogFactory.getLog(FileMovingTasklet.class);
public Resource getSourceDirectory() {
return sourceDirectory;
}
public void setSourceDirectory(Resource sourceDirectory) {
this.sourceDirectory = sourceDirectory;
}
public Resource getTargetDirectory() {
return targetDirectory;
}
public void setTargetDirectory(Resource targetDirectory) {
this.targetDirectory = targetDirectory;
}
#Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(sourceDirectory, "Source directory must be set");
Assert.notNull(targetDirectory, "Target directory must be set");
}
#Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
InputStream inStream = null;
OutputStream outStream = null;
File[] files;
File dir = sourceDirectory.getFile();
Assert.state(dir.isDirectory());
files = dir.listFiles();
File bfile = null;
for (int i = 0; i < files.length; i++) {
bfile = new File(targetDirectory.getURL().getPath() + File.separator + files[i].getName());
inStream = new FileInputStream(files[i]);
outStream = new FileOutputStream(bfile);
byte[] buffer = new byte[1024];
int length;
// copy the file content in bytes
while ((length = inStream.read(buffer)) > 0) {
outStream.write(buffer, 0, length);
}
inStream.close();
outStream.close();
}
return RepeatStatus.FINISHED;
}
Related
I am trying to run spring batch job run infinitely. Main motive is that dont allow to spring batch sit idle
I am using below code to run job infinitely
private JobExecution execution = null;
#Scheduled(cron = "0 */2 * * * ?")
public void perform() throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException {
System.out.println("=== STATUS STARTED ====");
if (execution != null && execution.isRunning()) {
System.out.println("Job is running. Please wait.");
return;
}
JobParameters jobParameters = new JobParametersBuilder().addString("JobId", String.valueOf(System.currentTimeMillis())).addDate("date", new Date()).addLong("time", System.currentTimeMillis()).toJobParameters();
execution = jobLauncher.run(job, jobParameters);
if (!execution.getStatus().isRunning()) {
perform();
}
System.out.println("STATUS :: " + execution.getStatus());
}
First we are checking that JOB is running or not. If not running then we re-run the same method again. Now job is running infinitely.
My question is that is this approach is good or bad? Or any other solution?
I have another query. If data is not available then break the infinite loop
How to break that loop..
FYI, Below is the batch configuration code
#Configuration
public class JobConfiguration {
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Autowired
private DataSource dataSource;
private Resource outputResource = new FileSystemResource("path\\output.csv");
private Resource inputResource = new FileSystemResource("path\\input.csv");
#Bean
public ColumnRangePartitioner partitioner() {
ColumnRangePartitioner columnRangePartitioner = new ColumnRangePartitioner();
columnRangePartitioner.setColumn("id");
columnRangePartitioner.setDataSource(dataSource);
columnRangePartitioner.setTable("customer");
return columnRangePartitioner;
}
#Bean
#StepScope
public FlatFileItemReader<Customer> pagingItemReader(#Value("#{stepExecutionContext['minValue']}") Long minValue, #Value("#{stepExecutionContext['maxValue']}") Long maxValue) {
System.out.println("reading " + minValue + " to " + maxValue);
// Create reader instance
FlatFileItemReader<Customer> reader = new FlatFileItemReader<>();
// Set input file location
reader.setResource(inputResource);
// Set number of lines to skips. Use it if file has header rows.
reader.setLinesToSkip(1);
// Configure how each line will be parsed and mapped to different values
reader.setLineMapper(new DefaultLineMapper() {
{
// 3 columns in each row
setLineTokenizer(new DelimitedLineTokenizer() {
{
setNames(new String[] { "id", "firstName", "lastName" });
}
});
// Set values in Employee class
setFieldSetMapper(new BeanWrapperFieldSetMapper<Customer>() {
{
setTargetType(Customer.class);
}
});
}
});
return reader;
}
#Bean
#StepScope
public FlatFileItemWriter<Customer> customerItemWriter() {
// Create writer instance
FlatFileItemWriter<Customer> writer = new FlatFileItemWriter<>();
// Set output file location
writer.setResource(outputResource);
// All job repetitions should "append" to same output file
writer.setAppendAllowed(true);
// Name field values sequence based on object properties
writer.setLineAggregator(new DelimitedLineAggregator<Customer>() {
{
setDelimiter(",");
setFieldExtractor(new BeanWrapperFieldExtractor<Customer>() {
{
setNames(new String[] { "id", "firstName", "lastName" });
}
});
}
});
return writer;
}
// Master
#Bean
public Step step1() {
return stepBuilderFactory.get("step1").partitioner(slaveStep().getName(), partitioner()).step(slaveStep()).gridSize(12).taskExecutor(new SimpleAsyncTaskExecutor()).build();
}
// slave step
#Bean
public Step slaveStep() {
return stepBuilderFactory.get("slaveStep").<Customer, Customer>chunk(1000).reader(pagingItemReader(null, null)).writer(customerItemWriter()).build();
}
#Bean
public Job job() {
return jobBuilderFactory.get("job").start(step1()).build();
}
}
Another way for running step continuously
<job id="notificationBatchJobProcess"
xmlns="http://www.springframework.org/schema/batch"
job-repository="jobRepository">
<step id="startLogStep" next="execute">
<tasklet ref="ref1" />
</step>
<step id="execute">
<batch:tasklet ref="ref2" />
<batch:next on="COMPLETED" to="endLogStep" />
</step>
<step id="endLogStep">
<batch:tasklet ref="ref3" />
<batch:next on="COMPLETED" to="startLogStep" />
</step>
</job>
What I am trying to achieve using above code once endLogStep task is completed then again it will call startLogStep.
And this process will continuing infinite time until or unless any exception is occurred.
Is this correct way for running those jobs?
I have been using Spring-Integration to call a REST api, however the http-client which comes by default with Spring-Integration does not support connection-pooling or reusability, so I customized to use PoolingHttpClientConnectionManager
But now Spring-integration stopped picking up the JKS files in my classpath, so I built my own SSL Context, however building this SSL Context caused significant drop in performance
For 100 concurrent threads,
Using http client I got 200 TPS
Using PoolingHttpClientConnectionManager and SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER, I got up to 380 TPS.
Building SSL context from JKS buildSslContext() I get less than 30 TPS :(
Context.xml
<int:gateway id="ServiceRequestGateway"
service-interface="com.company.security.integration.RequestGateway"
default-request-channel="RequestChannel"
default-reply-channel="ResponseChannel">
<int:default-header name="Accept" value="application/json; v=5"/>
<int:default-header name="Content-Type" value="application/json; v=5"/>
<int:default-header name="ServiceType" expression="#args[1]"/>
</int:gateway>
<int-http:outbound-gateway
id="Outbound_Gateway"
request-channel="RequestChannel"
reply-channel="ResponseChannel"
request-factory="requestFactory"
header-mapper="headerMapper"
url="${service.host}/{xyzServiceType}"
http-method="POST"
expected-response-type="java.lang.String"
extract-request-payload="true">
<int-http:uri-variable name="ServiceType" expression="headers['xyzServiceType']" />
</int-http:outbound-gateway>
<!--Connection Pooling/Keep Alive/Retry-->
<bean id="httpClient" class="com.capitalone.security.config.PooledCloseableHttpClient">
</bean>
<bean id="requestFactory"
class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<constructor-arg ref="httpClient"/>
<property name="connectTimeout" value="5000"/>
<property name="readTimeout" value="5000"/>
</bean>
PooledCloseableHttpClient
public class PooledCloseableHttpClient implements FactoryBean {
#Autowired
S3ClientUtil s3Client;
// For TLS/SSL connectivity from this client to service
#Value("${jks.filename}")
String jksFile;
// Password for Java keystores
#Value("${keystore.password}")
String keystorePassword;
private int maxRetries = 2;
//1 second
#Value("${rest.call.request.retryInterval:1000}")
private int retryInterval = 1000;
#Value("${rest.call.request.keepAliveTime:60}")
private int keepAliveTime = 60;
#Value("${rest.call.request.maxConnection:200}")
private int maxConnection = 200;
#Value("${rest.call.request.maxConnectionsPerRoute:100}")
private int maxConnectionsPerRoute = 100 ;
SSLConnectionSocketFactory sslConnectionSocketFactory;
// Custom Keep-Alive
ConnectionKeepAliveStrategy keepAliveStrategy = (response, context) -> {
HeaderElementIterator it = new BasicHeaderElementIterator
(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
HeaderElement he = it.nextElement();
String param = he.getName();
String value = he.getValue();
if (value != null && param.equalsIgnoreCase
("timeout")) {
return Long.parseLong(value) * 1000;
}
}
return keepAliveTime * 1000;
};
// Called once during initialization to get JKS file from Cloud
private SSLContext buildSslContext() {
try {
// Get the JKS contents and then use the pooling connection manager below
File keyStoreFile = s3Client.importKeystoreFile(jksFile);
// Build key store from JKS file downloaded from S3
final KeyStore keyStore = KeyStore.getInstance("JKS");
InputStream is = null;
try {
is = new FileInputStream(keyStoreFile); // Get Keystore
keyStore.load(is, keystorePassword.toCharArray()); //Get keystore password
} finally {
IOUtils.closeQuietly(is);
}
// Build SSL Context
SSLContextBuilder sslBuilder = new SSLContextBuilder();
sslBuilder.loadKeyMaterial(keyStore, keystorePassword.toCharArray());
sslBuilder.loadTrustMaterial(keyStoreFile, keystorePassword.toCharArray());
return sslBuilder.build();
} catch (final GeneralSecurityException | IOException exc) {
return null;
}
}
#Override
public Object getObject() throws Exception {
//Build PoolingHttpClientConnectionManager
PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(
RegistryBuilder.<ConnectionSocketFactory> create()
.register("https", new SSLConnectionSocketFactory(buildSslContext(), new NoopHostnameVerifier()))
.register("http", new PlainConnectionSocketFactory()).build());
// Build HttpClient
HttpClientBuilder httpClientBuilder = HttpClients.custom().useSystemProperties().setConnectionManager(poolingConnectionManager)
.setKeepAliveStrategy(keepAliveStrategy)
.setSSLSocketFactory(sslConnectionSocketFactory)
.setServiceUnavailableRetryStrategy(new ServiceUnavailableRetryStrategy(maxRetries, retryInterval));
return httpClientBuilder.build();
}
#Override
public Class<?> getObjectType() {
return CloseableHttpClient.class;
}
#Override
public boolean isSingleton() {
return true;
}
}
Here is the refactored HttpClient class which gave me the optimum performance.
public class PooledCloseableHttpClient implements FactoryBean {
#Autowired
S3ClientUtil s3Client;
// For TLS/SSL connectivity from this client to service
#Value("${jks.filename}")
String jksFile;
// Password for Java keystores
#Value("${keystore.password}")
String keystorePassword;
private int maxRetries = 2;
//1 second
#Value("${rest.call.request.retryInterval:1000}")
private int retryInterval = 1000;
#Value("${rest.call.request.keepAliveTime:60}")
private int keepAliveTime = 60;
#Value("${rest.call.request.maxConnection:200}")
private int maxConnection = 200;
#Value("${rest.call.request.maxConnectionsPerRoute:100}")
private int maxConnectionsPerRoute = 100 ;
SSLConnectionSocketFactory sslConnectionSocketFactory;
// Custom Keep-Alive
ConnectionKeepAliveStrategy keepAliveStrategy = (response, context) -> {
HeaderElementIterator it = new BasicHeaderElementIterator
(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
HeaderElement he = it.nextElement();
String param = he.getName();
String value = he.getValue();
if (value != null && param.equalsIgnoreCase
("timeout")) {
return Long.parseLong(value) * 1000;
}
}
return keepAliveTime * 1000;
};
// Called once during initialization to get JKS file from Cloud
private SSLContext buildSslContext() {
try {
// Get the JKS contents and then use the pooling connection manager below
File keyStoreFile = s3Client.importKeystoreFile(jksFile);
// Build key store from JKS file downloaded from S3
final KeyStore keyStore = KeyStore.getInstance("JKS");
InputStream is = null;
try {
is = new FileInputStream(keyStoreFile); // Get Keystore
keyStore.load(is, keystorePassword.toCharArray()); //Get keystore password
} finally {
IOUtils.closeQuietly(is);
}
// Build SSL Context
SSLContextBuilder sslBuilder = new SSLContextBuilder();
sslBuilder.loadKeyMaterial(keyStore, keystorePassword.toCharArray());
sslBuilder.loadTrustMaterial(keyStoreFile, keystorePassword.toCharArray());
return sslBuilder.build();
} catch (final GeneralSecurityException | IOException exc) {
return null;
}
}
#Override
public Object getObject() throws Exception {
//Build PoolingHttpClientConnectionManager
PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(
RegistryBuilder.<ConnectionSocketFactory> create()
.register("https", new SSLConnectionSocketFactory(buildSslContext(), new NoopHostnameVerifier()))
.register("http", new PlainConnectionSocketFactory()).build())
poolingConnectionManager.setMaxTotal(maxConnection);
poolingConnectionManager.setDefaultMaxPerRoute(maxConnectionsPerRoute);
// Build HttpClient
HttpClientBuilder httpClientBuilder = HttpClients.custom().useSystemProperties().setConnectionManager(poolingConnectionManager)
.setKeepAliveStrategy(keepAliveStrategy)
.setSSLSocketFactory(sslConnectionSocketFactory)
.setConnectionReuseStrategy((arg0, arg1) -> true)
.setMaxConnTotal(maxConnection)
.setMaxConnPerRoute(maxConnectionsPerRoute)
.setServiceUnavailableRetryStrategy(new ServiceUnavailableRetryStrategy(maxRetries, retryInterval));
return httpClientBuilder.build();
}
#Override
public Class<?> getObjectType() {
return CloseableHttpClient.class;
}
#Override
public boolean isSingleton() {
return true;
}
}
I am new to BigData I have written a MR program and trying to write test cases for it using MRUnit from https://dzone.com/articles/testing-mapreduce-mrunit
But My MR program has 2 mappers and 1 reducer so i am not able to create a driver object using
newMapReduceDriver()
newMapReduceDriver(mapper,reducer)
newMapReduceDriver(mapper,reducer,combiner)
or
newMultipleInputMapReduceDriver()
newMultipleInputMapReduceDriver(combiner,reducer)
newMultipleInputMapReduceDriver(reducer)
Please suggestion any other way of I am doing something wrong.Thanks in advance
Here is the code
public class UC_RJoinerTool extends Configured implements Tool{
public int run(String[] args) throws Exception {
if(args == null || args.length < 4 ){
System.err.println("Usage: <User file Input Path> <Comments file Input Path> <Output Path> <Inner/Right Outer/Full join>");
ToolRunner.printGenericCommandUsage(System.err);
return -1;
} else {
Job job = Job.getInstance(getConf(), "Mapping Users with Comments");
job.setJarByClass(UC_RJoinerTool.class);
Path userInputPath = new Path(args[0]);
Path commentsInputPath = new Path(args[1]);
Path outPutPath = new Path(args[2]);
String joinTypeInput = args[3];
MultipleInputs.addInputPath(job, userInputPath, TextInputFormat.class,UserDotXmlMapper.class);
MultipleInputs.addInputPath(job, commentsInputPath, TextInputFormat.class,CommentsDotXmlMapper.class);
FileOutputFormat.setOutputPath(job,new Path(args[1]));
//When you are using TextInputFormat explicitly say the map key and value types
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
job.getConfiguration().set("joinType",joinTypeInput);
job.setReducerClass(UserCommentsReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
FileOutputFormat.setOutputPath(job, outPutPath);
return job.waitForCompletion(true)?0:1;
}
}
public static void main(String[] args)throws Exception {
int exitCode = ToolRunner.run(new UC_RJoinerTool(),args);
System.exit(exitCode);
}
}
My Unit testCase Code
public class UCJoinTest {
private MapDriver<LongWritable,Text,Text,Text> mapUsersDriver,mapCommentsDriver;
private ReduceDriver<Text, Text, Text,Text> reduceUCDriver;
//private MapReduceDriver<LongWritable,Text,Text, Text, Text,Text> mapReduceUCDriver;
private MultipleInputsMapReduceDriver<LongWritable,Text,Text,Text> mapReduceUCDriver;
private MapDriver<LongWritable, Text, LongWritable,Text> mapSortDriver;
private ReduceDriver<LongWritable,Text,Text,Text> reduceSortDriver;
private MapReduceDriver<LongWritable,Text,LongWritable,Text,Text,Text> mapReduceSortDriver;
#Before
public void setUp() throws Exception {
final UserDotXmlMapper usersMapper = new UserDotXmlMapper();
final CommentsDotXmlMapper CommentsMapper = new CommentsDotXmlMapper();
final UserCommentsReducer ucReducer = new UserCommentsReducer();
final ReputationSorterMapper sortMapper = new ReputationSorterMapper();
final ReputationSorterReducer sortReducer = new ReputationSorterReducer();
mapUsersDriver = MapDriver.newMapDriver(usersMapper);
mapCommentsDriver = MapDriver.newMapDriver(CommentsMapper);
reduceUCDriver = ReduceDriver.newReduceDriver(ucReducer);
mapReduceUCDriver = MapReduceDriver.newMapReduceDriver(usersMapper,CommentsMapper,ucReducer);
mapReduceUCDriver = MultipleInputsMapReduceDriver.newMultipleInputMapReduceDriver(usersMapper,CommentsMapper,ucReducer);
mapSortDriver = MapDriver.newMapDriver(sortMapper);
reduceSortDriver = ReduceDriver.newReduceDriver(sortReducer);
mapReduceSortDriver = MapReduceDriver.newMapReduceDriver(sortMapper,sortReducer);
}
public class CommentsDotXmlMapper extends Mapper<LongWritable,Text,Text,Text>{
}
public class UserDotXmlMapper extends Mapper<LongWritable,Text,Text,Text>{
}
public class UserCommentsReducer extends Reducer<Text, Text, Text,Text>{
}
For some reason Stackowerflow was not allowing me to post a question so I am adding this comment please ignore this
How to get push notification working after manually closing UI on Android?
Hi, I need some help, Couldn't find any solutions by searching.
Application basically is like any other messaging applications, ex. Whatsapp.
I have MessageService running as own process, even UI closed, it stays alive.
This is how my application basically works:
MainActivity start service
MessageService send broadCast to
messageReceiver gets broadCast and run messageLoader
MessagesLoader extends AsyncTask gets changes from database
MessagesLoader push notification.
Every these parts working correctly when UI running
When I close UI, messageService restarts again, but no push notifications after UI closed.
Any help to get this work would be appreciated.
Thanks
Here is some code snippet to understand how my thing works..
MainActivity.java
...........................
#Override
protected void onResume() {
super.onResume();
serviceIntent = new Intent(getApplicationContext(), MessageService.class);
startService(serviceIntent);
registerReceiver(messageReceiver, new IntentFilter(MessageService.MESSAGES_BROADCAST_ACTION));
}
...........................
MessageService.java
public class MessageService extends Service {
Updater updater;
BroadcastReceiver messageBroadcaster;
Intent intent;
Context context;
static final public String MESSAGES_BROADCAST_ACTION = "com.<Your Package>";
public MessageService() {
}
#Override
public IBinder onBind(Intent intent) {
this.intent = intent;
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onCreate() {
super.onCreate();
this.updater = new Updater();
this.context = getApplicationContext();
this.intent = new Intent(this, NotificationActivity.class);
Toast.makeText(this, "Message Service Created", Toast.LENGTH_LONG).show();
}
#Override
public synchronized int onStartCommand(Intent intent, int flags, int startId) {
if (!updater.isRunning()) {
updater.start();
updater.isRunning = true;
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public synchronized void onDestroy() {
super.onDestroy();
if (updater.isRunning) {
updater.interrupt();
updater.isRunning = false;
updater = null;
}
Toast.makeText(this, "Message Service Destroyed", Toast.LENGTH_LONG).show();
}
class Updater extends Thread {
public boolean isRunning = false;
public long DELAY = 2500;
#Override
public void run() {
super.run();
isRunning = true;
while (isRunning) {
sendResult();
try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {
e.printStackTrace();
isRunning = false;
}
}
}
public boolean isRunning() {
return this.isRunning;
}
}
public void sendResult() {
sendBroadcast(intent);
}
}
MessageReceiver.java
public class MessageReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(context, MessageService.class);
context.startService(serviceIntent);
new MessagesLoader(context).execute();
}
}
MessageLoader.java
public class MessagesLoader extends AsyncTask<String,Void,String> {
public MessagesLoader(Context context) {
this.context = context;
this.intent = new Intent(this.context, ChatsActivity.class);
this.prev_count = prev_count;
Intent intent = new Intent(context, ChatsActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(context, 0, intent, 0);
this.mBuilder = new android.support.v4.app.NotificationCompat.Builder(context)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("YOUR APP");
}
protected void onPreExecute(){
}
#Override
protected String doInBackground(String... arg0) {
StringBuffer result = new StringBuffer("");
try {
URL url = new URL("http://yourURL.com/get_data.php");
HttpURLConnection con = (HttpURLConnection)url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("User-Agent", "");
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
con.setDoOutput(true);
String urlParameters = "<OWN PARAMETERS>";
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(urlParameters);
wr.flush();
wr.close();
int responseCode = con.getResponseCode();
con.connect();
InputStream inputStream = con.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(inputStream));
String line = "";
while ((line = rd.readLine()) != null) {
result.append(line);
}
return new String(result);
} catch(Exception e){
return new String("Exception: " + e.getMessage());
}
}
#Override
protected void onPostExecute(String result) {
initData(result);
}
public void initData(String result) {
// Actually Store Data to sharedPreferences
String error = "";
JSONObject obj = new JSONObject();
// ...ETC
int count = 5;
showNotification(5);
}
public void showNotification(int count) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent mIntent = new Intent(this.context, ChatsActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(this.context, 0, mIntent, 0);
Intent cIntent = new Intent(this.context, NotificationActionService.class);
PendingIntent cPIntent = PendingIntent.getService(this.context, 0, cIntent, 0);
NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle();
bigTextStyle.bigText("YOUR BIG TEXT");
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
mBuilder
.setContentIntent(pIntent)
.setContentText("YOUR CONTENT TEXT")
.setAutoCancel(true)
.setLights(R.color.white, 1000, 500)
.setSound(soundUri)
.setGroup("YOUR GROUP")
.setTicker("YOUR TICKER TEXT")
.setWhen(System.currentTimeMillis())
.setCategory("YOUR CATEGORY")
.setStyle(bigTextStyle)
.addAction(0, "Show Messages", pIntent);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(mIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yourpackage" >
android:versionCode="1"
android:versionName="1.0"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:configChanges="orientation"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.yourpackage.MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<service android:name="com.yourpackage.MessageService"
android:process=":messageService"
android:enabled="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/messageService">
<intent-filter>
<action android:name="com.yourpackage.MessageService" />
</intent-filter>
</service>
<receiver android:name="com.yourpackage.MessageReceiver">
<intent-filter>
<action android:name="com.yourpackage.MessageReceiver" />
</intent-filter>
</receiver>
</application>
</manifest>
I've found the solution. Now my application is always showing me new messages info even without UI running.
Here is solution to fix this problem.
MainActivity.java
#Override
protected void onResume() {
super.onresume();
serviceIntent = new Intent(getApplicationContext(), MessageService.class);
startService(serviceIntent);
/* COMMENTED OUT LINE BELOW */
//registerReceiver(messageReceiver, new IntentFilter(MessageService.MESSAGES_BROADCAST_ACTION));
}
MessageService.java
#Override
public void onCreate() {
super.onCreate();
updater = new Updater();
context = getApplicationContext();
/* AND ADDED THAT LINE HERE AND */
registerReceiver(messageReceiver, new IntentFilter(MESSAGES_BROADCAST_ACTION));
intent = new Intent(MESSAGES_BROADCAST_ACTION);
Toast.makeText(this, "Message Service Created", Toast.LENGTH_LONG).show();
}
I have a working sftp inbound channel adapter defined in the config xml (apparently defining this via annotations is not fully functional in Spring as yet).
What I would like to do is override the synchronizeToLocalDirectory method so that it can be manually activated with the help of JMX.
Instantiating the class with #Component happens, however the synchronizeToLocalDirectory in my class never gets called because it is separate to the actually bean invoked by Spring though the config xml.
Is there a way to pair the two so that my synchronizeToLocalDirectory method is called every time?
My Inbound File Synchronizer :
#Component
#ManagedResource(objectName = "bean:name=InboundFileProcessor", description = "Synchronizes to the Local Directory",
log = true, logFile = "jmx.log", currencyTimeLimit = 15, persistPolicy = "OnUpdate", persistPeriod = 200,
persistLocation = "Spring", persistName = "FTP")
public class MyFtpInboundFileSynchronizer extends AbstractInboundFileSynchronizer<LsEntry> {
private static final Logger logger = LoggerFactory.getLogger(MyFtpInboundFileSynchronizer.class);
#Inject
private MultiMarkupFilter multiMarkupFilter;
#Inject
public MyFtpInboundFileSynchronizer(SessionFactory<LsEntry> ftpSessionFactory) {
super(ftpSessionFactory);
setRemoteDirectory(((FtpSessionFactory) ftpSessionFactory).getFtpSessionProperties().getRemoteDirectory());
setFilter(multiMarkupFilter);
}
public void init() {
}
#Override
protected boolean isFile(LsEntry lsEntry) {
if (lsEntry != null && !lsEntry.getAttrs().isDir()
&& !lsEntry.getFilename().equals(".")
&& !lsEntry.getFilename().equals("..")) {
logger.debug("Downloading file" + lsEntry.getFilename());
return true;
} else {
return false;
}
}
#Override
protected String getFilename(LsEntry file) {
return (file != null ? file.getFilename() : null);
}
#Override
public void synchronizeToLocalDirectory(File localDirectory) {
logger.debug("Starting synchronizeToLocalDirectory");
super.synchronizeToLocalDirectory(localDirectory);
logger.debug("Ending synchronizeToLocalDirectory");
}
#ManagedOperation(description = "synchronize To Local Directory")
#ManagedOperationParameters({ #ManagedOperationParameter(name = "localDirectory", description = "The Local Directory") })
public void synchronizeToLocalDirectory(String localDirectory) {
File localDirFile = new File(localDirectory);
if (localDirFile.exists() && localDirFile.isDirectory()) {
synchronizeToLocalDirectory(new File(localDirectory));
}
}
}
int-sftp:inbound-channel-adapter definition :
<int:annotation-config/>
<int-sftp:inbound-channel-adapter id="ftpInbound"
channel="ftpChannel" session-factory="${sessionFactory}"
auto-create-local-directory="${autoCreateLocalDirectory}"
delete-remote-files="${deleteRemoteFiles}" filter="${filter}"
remote-directory="${remoteDirectory}"
remote-file-separator="${remoteFileSeparator}"
local-directory="${localDirectory}">
<int:poller max-messages-per-poll="-1"
fixed-rate="${ftpPollInterval}" id="poller" error-channel="errorChannel" >
</int:poller>
</int-sftp:inbound-channel-adapter>
<int:channel id="ftpChannel"/>
<int:channel id="errorChannel"/>