Stop/mute playing music using JLayer [closed] - mute

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
i am using jlayer to play mp3 files in my progam but in the jlayer documentation i could not find any useful info about stopping the playing music and continuing from where it was stopped. any ideas?
my program is as follows:
package sounds;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import javazoom.jl.player.Player;
/**
* Wayne, K. (2005). How to Play an MP3 File in Java.
* Available: http://introcs.cs.princeton.edu/faq/mp3/mp3.html.
* Last accessed 10th Mar 2011.
* #author temelm
*/
public class MP3 {
private String filename;
private Player player;
/**
* MP3 constructor
* #param filename name of input file
*/
public MP3(String filename) {
this.filename = filename;
}
/**
* Creates a new Player
*/
public void play() {
try {
FileInputStream fis = new FileInputStream(this.filename);
BufferedInputStream bis = new BufferedInputStream(fis);
this.player = new Player(bis);
} catch (Exception e) {
System.err.printf("%s\n", e.getMessage());
}
new Thread() {
#Override
public void run() {
try {
player.play();
} catch (Exception e) {
System.err.printf("%s\n", e.getMessage());
}
}
}.start();
}
/**
* Closes the Player
*/
public void close() {
if (this.player != null) {
this.player.close();
}
}
/////////////////////////
/**
* Plays '01 Maenam.mp3' in an infinite loop
*/
public static void playMaenam() {
MP3 mp3 = new MP3("./01 Maenam.mp3");
mp3.play();
while (true) {
if (mp3.player.isComplete()) {
mp3.close();
mp3.play();
}
}
}
}

You could suspend its thread for a simple pause function.

Just play one frame at a time in the thread, if the "pause" flag is set, then pause the thread...
The code below pauses/resumes the player thread if enter key is pressed (in console) and "exit" to terminate the application.
final AtomicBoolean pause = new AtomicBoolean(false);
final Player player = new Player(bis);
Thread playerThread = new Thread() {
#Override
public void run() {
try {
while (player.play(1)) {
if(pause.get()) {
LockSupport.park();
}
}
}
catch (Exception e) {
System.err.printf("%s\n", e.getMessage());
}
}
};
playerThread.start();
Scanner scanner = new Scanner(System.in);
String s = null;
while (!(s = scanner.nextLine()).equals("exit")) {
if (s.isEmpty()) {
pause.set(!pause.get());
if (!pause.get()) {
LockSupport.unpark(playerThread);
}
}
}
System.exit(0);

I get my mp3's from a fileInputStream. When I want to pause, I do (fis is the fileinputstream) fis.available() (or something similar). This gives how many bytes left in the stream... If you do this before it starts, you get the total length. So total left - amount currently left = Current position. Then i just create a new inputstream and do fis.skip(theamount); to resume.. Aweful method but yeah it works..

Related

How to enable Platform.runlater within method

I am creating a Javafx chat app which also allows for file transfer. My issue is I open a FileOutputStream for the received file within the below method. I can see my listener.statusTransferring() updating the UI only if I enable Platform.runLater. I think I now need to enable the same on the fos.write(b, 0, tmpTransferred) within the while loop but don't know how to do this. I have tried unsuccessfully wrapping the whole method within Platform runlater. Note: If I don't use platform runlater I don't get any errors however the UI does not update until the file transfer is complete eg listener.statusCompleted() is called;. The error I get now as a result of the fos being in Platform runlater. is below.. Line 185 is fos.write(b, 0, tmpTransferred); The other listener calls appear to work fine. Just not listener.statusTransferring(); or listener.transferUpdate(); which utilise the fos. Any help will be greatly appreciated. Also for your own sanity I am a self taught google programmer. Yep the worst kind I am sure. Thanks in advance.
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at net.thebowdens.net.FileReceiver.transfer(FileReceiver.java:185)
at net.thebowdens.net.DefaultMessageResponder.fileSend(DefaultMessageResponder.java:543)
public boolean transfer() {
listener.statusConnecting();
received = false;
cancel = false;
try {
if (sSock != null) {
sock = sSock.accept();
listener.statusTransferring();
Platform.runLater(() ->{
try {
fos = new FileOutputStream(file);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
is = sock.getInputStream();
final byte[] b = new byte[1024];
transferred = 0;
percent = 0;
int tmpTransferred = 0;
int tmpPercent = 0;
int transCounter = 0;
bCounter.prepare();
while (!cancel && (tmpTransferred = is.read(b)) != -1) {
fos.write(b, 0, tmpTransferred);
transferred += tmpTransferred;
percent = (int) ((transferred * 100) / size);
bCounter.addBytes(tmpTransferred);
transCounter++;
if (percent > tmpPercent || transCounter >= 250) {
transCounter = 0;
tmpPercent = percent;
listener.transferUpdate();
}
}
if (!cancel && transferred == size) {
received = true;
listener.statusCompleted();
}
else {
listener.statusFailed();
}
}
}
catch (final IOException e) {
LOG.log(Level.SEVERE, e.toString());
listener.statusFailed();
}
finally {
stopReceiver();
cleanupConnections();
}
return received;
}
Keep in mind that you should use Platform.runLater only for updating the UI, everything else should be outside it otherwhise the UI will become unresponsive.
I suggest you to to refactor your code according to this.
Well after much discussion over the correct language and other issues I solved my problem of the UI updating. I had two issues. My choice selector and Filechooser methods were not on the Javafx application thread (hope this is the right terminology) so I had to do the following:
private ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(new Runnable() {
#Override
public void run() {
Platform.runLater(() -> {
try {
receiveRequest(tmpUser, fileRes, user, fileName, size, fileHash);
} catch (IOException | ServerException | CommandException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
}
});
I then had to do the same within the Filechooser and file accept method for the transfer class UI to update
executorService.execute(new Runnable() {
#Override public void run() {
if (fileRes.transfer()) {
ui.showSystemMessage("Successfully received " + fileName +
" from " + user + ", and saved as " + fileRes.getFile().getName());
}
else {
ui.showSystemMessage("Failed to receive " + fileName + " from " + user);
fileRes.cancel();
}
}
});
}

Method checks for lock, runs after lock released

Im facing a potential chase error. Im using javafx TableView to display my data, and I'm periodically receiving an update request externally which calls my update function. I also have some listeners which does stuff such as handle mousedrag events etc. What i want to do is to do something like this:
private void handleEvent(){
TableView.setRowFactory(new Callback<TableView<MyModel>, TableRow<MyModel>>(){
public TableRow<MyModel> call(TableView<MyModel> p) {
final TableRow row = new TableRow();
row.setOnDragDetected(new EventHandler<MouseEvent>(){
public void handle(){
//implement some kind of lock to prevent receiving data update
}
}
row.setOnMouseDragExited(new EventHandler<MouseDragEvent>(){
//release lock to accept update
}
}
}
//this method is being called externally periodically
public void updateModel(MyModel model){
//this won't work because it will skip entirely if it's locked,
//I want it to instead run later when lock is released
if (!locked){
this.model = model;
}
}
I did a quick workaround by using a Boolean to lock and unlock as shown in updateModel Method, problem with that is it will lose some updated data because it's skipped entirely.. instead, I want it to run later when lock is released.. how can I implement this kind of lock mechanism and run later feature?
Edit: why I suspect this is because my listeners are manipulating and getting table data.. while the data is constantly updated, I'm not sure if this is causing my table to break.
Just write some logic that collects everything you tried to do in a locked state and executes it on unlocking.
The following code assumes you're using Platform.runLater or similar code that makes the update run on the application thread.
public class UpdateSynchronizer {
private final List<Runnable> pendingUpdates = new ArrayList<>();
private boolean locked = false;
public void lock() {
if (locked) {
throw new IllegalStateException("double lock");
} else {
locked = true;
}
}
public void runUpdate(Runnable updater) {
if (updater == null) {
throw new IllegalArgumentException();
}
if (locked) {
pendingUpdates.add(updater);
} else {
updater.run();
}
}
public void unlock() {
for (Runnable r : pendingUpdates) {
try {
r.run();
} catch(Exception ex) {
ex.printStackTrace(); // print but ignore
}
}
pendingUpdates.clear();
locked = false;
}
}
If the last update always overwrites all the data from previous updates, simply keeping a single Runnable instead of a list of them would be more performant.
private final UpdateSynchronizer synchronizer = new UpdateSynchronizer();
// why did all the keywords start with uppercase letters (compile time error)
private void handleEvent(){
TableView.setRowFactory(new Callback<TableView<myModel>, TableRow<myModel>>(){
public TableRow<myModel> call(TableView<myModel> p) {
final TableRow row = new TableRow();
row.setOnDragDetected(new EventHandler<MouseEvent>(){
public void handle(){
synchronizer.lock();
//implement some kind of lock to prevent receiving data update
}
}
row.setOnMouseDragExited(new EventHandler<MouseDragEvent>(){
//release lock to accept update
synchronizer.unlock();
}
}
}
//this method is being called externally periodically
public void updateModel(myModel model){
synchronizer.runUpdate(() -> {
// this is just an assignment and won't have any side effects
// updates to the scene may only happen, if the model is accessed in some event handler or animation
this.model = model;
});
}

CSV File Not Being Read from Servlet

As the title says, I have a CSV file that will not load from within my web application. I am using Netbeans to build the project.
Whenever I launch the project from Netbeans, it works like it should however when I take the war file and try to deploy it from within the Glassfish interface it shows the variables as undefined which tells me that it is not reading the file. Screenshots below show what is happening and my folder structure.
I have read many posts here and #BalusC has some great information here, but its not working for me and I believe this is somehow my fault, but I need a bit more specific help here than just reading another post.
I have put the CSV file that I am intending to load into the /src/main/resources folder as noted here by BalusC. The code I am using to load the file is as follows.
As a side note, I have a JSP that I am using to check the location and access to the file. The JSP can access and display the file without any problems when the application is deployed manually.
Edit: I ran a debug and could not find anything wrong, so I ran glassfish in verbose mode and loaded the page, once the page was up, it started reading from the file and sending the data but still shows "undefined" in all fields.
Here is the output data from running glassfish in verbose mode.
[#|2017-05-05T16:34:37.609+0900|INFO|glassfish 4.1|DukeETFServlet|_ThreadID=33;_ThreadName=http-listener-1(3);_TimeMillis=1493969677609;_LevelValue=800;|
Connection open.|#]
[#|2017-05-05T16:34:38.014+0900|INFO|glassfish 4.1|DukeETFServlet|_ThreadID=109;_ThreadName=__ejb-thread-pool3;_TimeMillis=1493969678014;_LevelValue=800;|
Sent: ABRN / Arbor Realty Trust 7.375% Senior / 25.32 / 25.11 / 25.24 / 12000 / 24.27 / 26.15 / Fri May 05 16:34:38 JST 2017|#]
[#|2017-05-05T16:34:38.016+0900|INFO|glassfish 4.1|DukeETFServlet|_ThreadID=109;_ThreadName=__ejb-thread-pool3;_TimeMillis=1493969678016;_LevelValue=800;|
Connection closed.|#]
[#|2017-05-05T16:34:38.024+0900|INFO|glassfish 4.1|DukeETFServlet|_ThreadID=34;_ThreadName=http-listener-1(4);_TimeMillis=1493969678024;_LevelValue=800;|
Connection open.|#]
[#|2017-05-05T16:34:38.029+0900|INFO|glassfish 4.1|DukeETFServlet|_ThreadID=119;_ThreadName=__ejb-thread-pool4;_TimeMillis=1493969678029;_LevelValue=800;|
Sent: ABT / Abbott Laboratories / 44.01 / 43.60 / 43.65 / 7487400 / 36.76 / 45.84 / Fri May 05 16:34:38 JST 2017|#]
Here is the data for loading the file.
Servlet
#WebServlet(urlPatterns={"/dukeetf"}, asyncSupported=true)
public class DukeETFServlet extends HttpServlet {
private static final Logger logger = Logger.getLogger("DukeETFServlet");
private static final long serialVersionUID = 2114153638027156979L;
private Queue<AsyncContext> requestQueue;
#EJB private PriceVolumeBean pvbean;
#Override
public void init(ServletConfig config) {
/* Queue for requests */
requestQueue = new ConcurrentLinkedQueue<>();
/* Register with the bean that provides price/volume updates */
pvbean.registerServlet(this);
}
/* PriceVolumeBean calls this method every second to send updates */
public void send(String ticker, String name, float highPrice, float lowPrice,
float closingPrice, int volume, float fiftyTwoWeekHigh, float fiftyTwoWeekLow,
String currentTime) {
/* Send update to all connected clients */
for (AsyncContext acontext : requestQueue) {
try {
String msg = String.format("%s / %s / %.2f / %.2f / %.2f / %d /"
+ " %.2f / %.2f / %s",
ticker, name, highPrice, lowPrice, closingPrice, volume,
fiftyTwoWeekHigh, fiftyTwoWeekLow, currentTime);
PrintWriter writer = acontext.getResponse().getWriter();
writer.write(msg);
logger.log(Level.INFO, "Sent: {0}", msg);
/* Close the connection
* The client (JavaScript) makes a new one instantly */
acontext.complete();
} catch (IOException ex) {
logger.log(Level.INFO, ex.toString());
}
}
}
/* Service method */
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
/* Put request in async mode. */
final AsyncContext acontext = request.startAsync();
/* Remove from the queue when done */
acontext.addListener(new AsyncListener() {
#Override
public void onComplete(AsyncEvent ae) throws IOException {
requestQueue.remove(acontext);
logger.log(Level.INFO, "Connection Being Closed.");
}
#Override
public void onTimeout(AsyncEvent ae) throws IOException {
requestQueue.remove(acontext);
logger.log(Level.INFO, "Connection Has Timed Out.");
}
#Override
public void onError(AsyncEvent ae) throws IOException {
requestQueue.remove(acontext);
logger.log(Level.INFO, "Connection error.");
}
#Override
public void onStartAsync(AsyncEvent ae) throws IOException { }
});
/* Add to the queue */
requestQueue.add(acontext);
logger.log(Level.INFO, "Connection Being Opened.");
}
}
Class to get information from CSV
//Get Stock Data From CSV File
public static ArrayList<Stock> getListOfStocks() throws IOException {
ArrayList<Stock> stocks = new ArrayList();
ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
InputStream is =
StockService.class.getResourceAsStream("/stockdata.csv");
// create an instance of BufferedReader
// using try with resource, Java 7 feature to close resources
try (CSVReader reader = new CSVReader(new InputStreamReader(is))) {
// read the first line from the text file
String[] nextLine;
reader.readNext();
// loop until all lines are read
while ((nextLine = reader.readNext()) != null) {
Stock newStock = new Stock(nextLine[0], nextLine[1],
Float.valueOf(nextLine[2]), Float.valueOf(nextLine[3]),
Float.valueOf(nextLine[4]), Integer.valueOf(nextLine[5]),
Float.valueOf(nextLine[6]), Float.valueOf(nextLine[7]));
stocks.add(newStock);
}
}
return stocks;
}
Bean that retrieves and sends information
/* Updates price and volume information every second */
#Startup
#Singleton
public class PriceVolumeBean {
/* Use the container's timer service */
#Resource TimerService tservice;
private DukeETFServlet servlet;
//Set Variable for Counter
private int i = 0;
//Set date time variable
String currentTime;
//Set Variables for Stock Data
private String ticker;
private String name;
private float highPrice;
private float lowPrice;
private float closingPrice;
private int volume;
private float fiftyTwoWeekHigh;
private float fiftyTwoWeekLow;
private static final Logger logger = Logger.getLogger("PriceVolumeBean");
#PostConstruct
public void init() {
/* Intialize the EJB and create a timer */
logger.log(Level.INFO, "Initializing EJB.");
servlet = null;
tservice.createIntervalTimer(2000, 2000, new TimerConfig());
}
public void registerServlet(DukeETFServlet servlet) {
/* Associate a servlet to send updates to */
this.servlet = servlet;
}
#Timeout
public void timeout() throws IOException {
// Update Date
Date date = new Date();
// Set stock variables //
ticker = StockService.getListOfStocks().get(i).getTicker();
name = StockService.getListOfStocks().get(i).getName();
highPrice = StockService.getListOfStocks().get(i).getHighPrice();
lowPrice = StockService.getListOfStocks().get(i).getLowPrice();
closingPrice = StockService.getListOfStocks().get(i).getClosingPrice();
volume = StockService.getListOfStocks().get(i).getVolume();
fiftyTwoWeekHigh = StockService.getListOfStocks().get(i).getFiftyTwoWeekHigh();
fiftyTwoWeekLow = StockService.getListOfStocks().get(i).getFiftyTwoWeekLow();
currentTime = date.toString();
// Send updated information
if (servlet != null)
servlet.send(ticker, name, highPrice, lowPrice, closingPrice,
volume, fiftyTwoWeekHigh, fiftyTwoWeekLow, currentTime);
// Counter that keeps from going beyond size of arraylist
i++;
if (i == 100) {
i = 0;
}
}
}

Can Storm's HdfsBolt flush data after a timeout as well?

We are using Storm to process streaming data and store into HDFS. We have got everything to work but have one issue. I understand that we can specify the number of tuples after which the data gets flushed to HDFS using SyncPolicy, something like this below:
SyncPolicy syncPolicy = new CountSyncPolicy(Integer.parseInt(args[3]));
The question I have is can the data also be flushed after a timeout? For e.g. we have set the SyncPolicy above to 1000 tuples. If for whatever reason we get 995 tuples and then the data stops coming in for a while is there any way that storm can flush the 995 records to HDFS after a specified timeout (5 seconds)?
Thanks in advance for any help on this!
Shay
Yes, if you send a tick tuple to the HDFS bolt, it will cause the bolt to try to sync to the HDFS file system. All this happens in the HDFS bolt's execute function.
To configure tick tuples for your topology, in your topology config. In Java, to set that to every 300 seconds the code would look like:
Config topologyConfig = new Config();
topologyConfig.put(Config.TOPOLOGY_TICK_TUPLE_FREQ_SECS, 300);
StormSubmitter.submitTopology("mytopology", topologyConfig, builder.createTopology());
You'll have to adjust that last line depending on your circumstances.
There is an alternative solution for this problem,
First, lets clarify about sync policy, If your sync policy is 1000 ,then HdfsBolt only sync the data from 1000 tuple by calling hsync() method in execute() means it only clears the buffer by pushing data to disk, but for faster write disk may uses its cache and not writing to file directly.
The data is written to the file only when the size of data matches your rotation policy that need to specify at the time of bolt creation.
FileRotationPolicy rotationPolicy = new FileSizeRotationPolicy(100.0f, Units.KB);
So for flushing the record the to file after timeout, Seperate your tick tuple from normal tuples in excecute method and calculate the time difference of both tuple, If the diff is greater than timeout period then write the data to file.
By handling tick tuple differently you can also avoid the tick tuple frequency written to your file.
See the below code for better understanding:
public class CustomHdfsBolt1 extends AbstractHdfsBolt {
private static final Logger LOG = LoggerFactory.getLogger(CustomHdfsBolt1.class);
private transient FSDataOutputStream out;
private RecordFormat format;
private long offset = 0L;
private int tickTupleCount = 0;
private String type;
private long normalTupleTime;
private long tickTupleTime;
public CustomHdfsBolt1() {
}
public CustomHdfsBolt1(String type) {
this.type = type;
}
public CustomHdfsBolt1 withFsUrl(String fsUrl) {
this.fsUrl = fsUrl;
return this;
}
public CustomHdfsBolt1 withConfigKey(String configKey) {
this.configKey = configKey;
return this;
}
public CustomHdfsBolt1 withFileNameFormat(FileNameFormat fileNameFormat) {
this.fileNameFormat = fileNameFormat;
return this;
}
public CustomHdfsBolt1 withRecordFormat(RecordFormat format) {
this.format = format;
return this;
}
public CustomHdfsBolt1 withSyncPolicy(SyncPolicy syncPolicy) {
this.syncPolicy = syncPolicy;
return this;
}
public CustomHdfsBolt1 withRotationPolicy(FileRotationPolicy rotationPolicy) {
this.rotationPolicy = rotationPolicy;
return this;
}
public CustomHdfsBolt1 addRotationAction(RotationAction action) {
this.rotationActions.add(action);
return this;
}
protected static boolean isTickTuple(Tuple tuple) {
return tuple.getSourceComponent().equals(Constants.SYSTEM_COMPONENT_ID)
&& tuple.getSourceStreamId().equals(Constants.SYSTEM_TICK_STREAM_ID);
}
public void execute(Tuple tuple) {
try {
if (isTickTuple(tuple)) {
tickTupleTime = Calendar.getInstance().getTimeInMillis();
long timeDiff = normalTupleTime - tickTupleTime;
long diffInSeconds = TimeUnit.MILLISECONDS.toSeconds(timeDiff);
if (diffInSeconds > 5) { // specify the value you want.
this.rotateWithOutFileSize(tuple);
}
} else {
normalTupleTime = Calendar.getInstance().getTimeInMillis();
this.rotateWithFileSize(tuple);
}
} catch (IOException var6) {
LOG.warn("write/sync failed.", var6);
this.collector.fail(tuple);
}
}
public void rotateWithFileSize(Tuple tuple) throws IOException {
syncHdfs(tuple);
this.collector.ack(tuple);
if (this.rotationPolicy.mark(tuple, this.offset)) {
this.rotateOutputFile();
this.offset = 0L;
this.rotationPolicy.reset();
}
}
public void rotateWithOutFileSize(Tuple tuple) throws IOException {
syncHdfs(tuple);
this.collector.ack(tuple);
this.rotateOutputFile();
this.offset = 0L;
this.rotationPolicy.reset();
}
public void syncHdfs(Tuple tuple) throws IOException {
byte[] e = this.format.format(tuple);
synchronized (this.writeLock) {
this.out.write(e);
this.offset += (long) e.length;
if (this.syncPolicy.mark(tuple, this.offset)) {
if (this.out instanceof HdfsDataOutputStream) {
((HdfsDataOutputStream) this.out).hsync(EnumSet.of(SyncFlag.UPDATE_LENGTH));
} else {
this.out.hsync();
}
this.syncPolicy.reset();
}
}
}
public void closeOutputFile() throws IOException {
this.out.close();
}
public void doPrepare(Map conf, TopologyContext topologyContext, OutputCollector collector) throws IOException {
LOG.info("Preparing HDFS Bolt...");
this.fs = FileSystem.get(URI.create(this.fsUrl), this.hdfsConfig);
this.tickTupleCount = 0;
this.normalTupleTime = 0;
this.tickTupleTime = 0;
}
public Path createOutputFile() throws IOException {
Path path = new Path(this.fileNameFormat.getPath(),
this.fileNameFormat.getName((long) this.rotation, System.currentTimeMillis()));
this.out = this.fs.create(path);
return path;
}
}
You can directly use this class in your project.
Thanks,

ServletContextListener threads

I'm currently having an issue with stopping a background thread in a webachive. I currently tie it in the war's deployment, and destroy it when the archive is un-deployed.
The threads starts up without issue, but when I close the archive, It seems to lose the handle on the thread. In the below case: st is null when the contextDestroyed method is called.
This is an issue as Tomcat notes the thread as orphaned in its warning about memory leaks.
public class LimitOrderContextListener implements ServletContextListener {
static Logger logger = Logger.getLogger(LimitOrderRuntime.class.getName());
private SwiftThread st = null;
/**
* Initializes this listener when this war's context is initialized
*/
public void contextInitialized(ServletContextEvent sce)
{
try {
if ( (st == null) || (!st.isAlive()) ) {
LimitOrderRuntime lor = new LimitOrderRuntime();
SwiftThread st = new SwiftThread(lor);
st.start();
} else {
st.gracefulStop();
st.join(2000);
}
} catch(Exception e) {
logger.warn("Unable to properly load thread! " +
e.getMessage() + " --cause " + e.getCause());
e.printStackTrace();
}
}
/**
* When this war is destroyed/stopped, stop the thread.
*/
public void contextDestroyed(ServletContextEvent sce)
{
try {
boolean success = st.gracefulStop();
if (!success) {
st.interrupt();
}
} catch (Exception e) {
logger.warn("Unable to properly release thread! " +
e.getMessage() + " --cause " + e.getCause());
e.printStackTrace();
}
}
}
In your contextInitialized method, you're redeclaring st as a local variable, rather than initializing the instance variable with the thread.
Replace
SwiftThread st = new SwiftThread(lor);
with
this.st = new SwiftThread(lor);

Resources