Triggering and Outputting events with Jersey SSE - java

I am new to using SSE with Jersey, and have the following situation.
I have a JAXB annotated class that represents and acts on the I/O of a Raspberry Pi (class GpioRepresentation).
The client class accesses the status of I/O through the method getUpdate() which returns the XML object
representation of the class.
#XmlRootElement
public class GpioRepresentation implements GpioSubject
{
...
/**
* Returns an object of this class with the current
* representation of the I/O states
* #return this
*/
public synchronized GpioRepresentation getUpdate()
{
this.getGarageDoorInputState();
this.getZoneOneFeedback();
this.getZoneTwoFeedback();
this.getZoneThreeFeedback();
this.getGarageDoorRelayState();
this.getZoneOneRelayState();
this.getZoneTwoRelayState();
this.getZoneThreeRelayState();
return this;
}
...
}
The client that uses getUpdate() is the class HomeResource, method getPiStatusStream(). This is a JAX-RS annotated method,
and provides remote clients Server Sent Events. Currently this method is written as shown here with a continuous loop
in a separate thread which polls for updates.
#Path("/homeservice")
#RolesAllowed({"ADMIN", "USER"})
#Produces(MediaType.APPLICATION_XML)
#Consumes(MediaType.APPLICATION_XML)
public class HomeResource
{
private static final Logger LOGGER = LoggerFactory.getLogger(HomeResource.class);
private GpioRepresentation piService;
...
/**
* gets status information on the Raspberry Pi's
* I/O and returns it to the client on a continuous basis
* and only if it changes.
* #return EventOutput
*/
#GET
#Path("/iostatus")
#Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput getPiStatusStream()
{
final EventOutput eventOutput = new EventOutput();
new Thread(new Runnable()
{
public void run()
{
try {
String gdState = null;
String zOneState = null;
String zTwoState = null;
String zThreeState = null;
String gdRState = null;
String zOneRState = null;
String zTwoRState = null;
String zThreeRState = null;
String lastgdState = null;
String lastzOneState = null;
String lastzTwoState = null;
String lastzThreeState = null;
String lastgdRState = null;
String lastzOneRState = null;
String lastzTwoRState = null;
String lastzThreeRState = null;
while(true) {
final OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
final GpioRepresentation iostatus = piService.getUpdate();
gdState = piService.getGarageDoorInputState();
zOneState = piService.getZoneOneFeedback();
zTwoState = piService.getZoneTwoFeedback();
zThreeState = piService.getZoneThreeFeedback();
gdRState = piService.getGarageDoorRelayState();
zOneRState = piService.getZoneOneRelayState();
zTwoRState = piService.getZoneTwoRelayState();
zThreeRState = piService.getZoneThreeRelayState();
if (!(gdState.equals(lastgdState) && zOneState.equals(lastzOneState) && zTwoState.equals(lastzTwoState) && zThreeState.equals(lastzThreeState)
&& gdRState.equals(lastgdRState) && zOneRState.equals(lastzOneRState) && zTwoRState.equals(lastzTwoRState) && zThreeRState.equals(lastzThreeRState)))
{
OutboundEvent event = eventBuilder.data(GpioRepresentation.class, iostatus)
.mediaType(MediaType.APPLICATION_XML_TYPE)
.build();
eventOutput.write(event);
lastgdState = gdState;
lastzOneState = zOneState;
lastzTwoState = zTwoState;
lastzThreeState = zThreeState;
lastgdRState = gdRState;
lastzOneRState = zOneRState;
lastzTwoRState = zTwoRState;
lastzThreeRState = zThreeRState;
}
Thread.sleep(100);
}
}
catch (Exception exeption)
{
System.err.println("Error: " + exeption);
}
finally
{
try
{
eventOutput.close();
}
catch (IOException ioClose)
{
throw new RuntimeException("Error when closing the event output.", ioClose);
}
}
}
}).start();
return eventOutput;
}
...
}
The issue I have and see with this is that this doesn't scale well. Creating a thread for every GET from a remote client
takes time, and eats CPU resources. Plus I don't think this is an elegant solution. What I would like to do
is encapsulate the event code into a separate class, and use some sort of observer pattern that can trigger the
creation of an event....however, how do I tie this into the resource method so that it can be returned to the
remote client?
Can anyone point me to some examples, or provide advice on designing a solution for this?

Solution was to utilize the SseBroadcaster class. I made the HomeService class an observer of the GpioRepresentation class, and then called a new method (broadcastIOUpdateMessage()) which then output my event to the remote client.
public void broadcastIOUpdateMessage()
{
GpioRepresentation iostatus = piService.getUpdate();
OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
OutboundEvent event = eventBuilder.data(GpioRepresentation.class, iostatus)
.mediaType(MediaType.APPLICATION_XML_TYPE)
.build();
broadcaster.broadcast(event);
}
#GET
#Path("/iostatus")
#Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput getPiStatusStream()
{
final EventOutput eventOutput = new EventOutput();
this.broadcaster.add(eventOutput);
return eventOutput;
}

Related

Using jsmpp for sending asynchronous messages to SMSC server

we have a message campaign where we send over 100k messages (SMS) a day. So we are a client of SMSC server. We have no influence on SMSC server code. Before some time, we had around 80-90 message per second, now frequency dropped to 15 messages per second, according to tcpdumps.
I have few information regarding this, so I will try to explain best as I can.
So we are using Spring Boot 2.7 and open source jsmpp (3.0.0) library for sending SMS messages (PDU commands) to SMSC.
While reading about protocol (page 40), I noticed that there is a way to send messages asynchronously by providing a seqence_number. The code example is here. But I am not sure if that is going to help...
The code:
#Component
public class ClientConfig {
#Autowired
private MessageReceiverListener msgListener;
#Autowired
private SessionStateListener sessionListener;
private SMPPSession session;
public String charset = "ISO-10646-UCS-2";
public long idleReceiveTimeout = 65000;
public long checkBindingTimeout = 12000;
public long timeout = 7000;
public int enquireLinkTimeout = 15000;
public String hostIp = "someIpAddress";
public int port = 5000;
public String final systemId = "someSystemId";
public String final password = "password";
public BindType bindType = BindType.BIND_TRX; //transceiver
public String systemType = null;
public String addressRange = null;
public TypeOfNumber addrTon = TypeOfNumber.UNKNOWN;
public NumberingPlanIndicator addrNpi = NumberingPlanIndicator.UNKNOWN;
protected synchronized void tryToConnectToSmsc() throws Exception {
try {
// Connect to host
BindParameter bp = new BindParameter(bindType, systemId, password, systemType, addrTon, addrNpi, addressRange);
session = new SMPPSession();
session.setEnquireLinkTimer(enquireLinkTimer);
session.connectAndBind(host, port, bp, timeout);
session.setMessageReceiverListener(msgListener);
session.addSessionStateListener(sessionListener);
}
// Main connection failed.
catch (Exception e) {
//log and re-attempt connection logic here
}
}
}
The listeners:
#Component
public class MySessionListenerImpl implements SessionStateListener {
#Override
public void onStateChange(SessionState newState, SessionState oldState, Session source) {
//TODO
}
}
#Service
public class SmsListenerImpl implements MessageReceiverListener {
#Override
public void onAcceptDeliverSm(DeliverSm deliverSm) throws ProcessRequestException {
//TODO
}
#Override
public void onAcceptAlertNotification(AlertNotification alertNotification) {}
#Override
public DataSmResult onAcceptDataSm(DataSm dataSm, Session session) throws ProcessRequestException {
return null;
}
}
Message sending service:
#Service
public class MessageSendingServiceImpl extends ClientConfig implements MessageSendingService{
private final ESMClass esmClass = new ESMClass();
private final byte protocolId = (byte) 0;
private final byte priorityFlag = (byte) 1;
private final TimeFormatter formatter = new AbsoluteTimeFormatter();
private final byte defaultMsgId = (byte) 0;
public SmsAdapterServiceImpl() {
super();
}
#PostConstruct
public synchronized void init() throws Exception {
super.tryToConnectToSmsc();
}
#Override
public String send(DomainObject obj){ //DomainObject -> contains fields: id, to, from, text, delivery, validity;
String serviceType = null;
//source
TypeOfNumber sourceTON = TypeOfNumber.NATIONAL; //there is some logic here which determines if it is INTERNATIOANL, ALPHANUMERIC etc...
NumberPlaningIndicator sourceNpi = NumberPlaningIndicator.ISDN; //constant...
String sourcePhone = obj.getFrom();
//destination
TypeOfNumber destinationTON = TypeOfNumber.NATIONAL; //there is some logic here which determines if it is INTERNATIOANL, ALPHANUMERIC etc...
NumberPlaningIndicator destinationNpi = NumberPlaningIndicator.ISDN; //constant...
String destinationPhone = obj.getTo();
String scheduledDeliveryTime = null;
if (obj.getDelivery() != null) scheduledDeliveryTime = formatter.format(obj.getDelivery());
String validityPeriodTime = null;
if (obj.getValidity() != null) validityPeriodTime = formatter.format(obj.getValidity());
Map<Short, OptionalParameter> optionalParameters = new HashMap<>();
String text = obj.getText();
if ( text.length() > 89 ) { //set text as payload instead of message text
OctetString os = new OctetString(OptionalParameter.Tag.MESSAGE_PAYLOAD.code(), text, "ISO-10646-UCS-2"); //"ISO-10646-UCS-2" - encoding
optionalParameters.put(os.tag, os);
text = "";
}
String msgId =
session.submitShortMessage( serviceType ,
sourceTON ,
sourceNpi ,
sourcePhone ,
destinationTON ,
destinationNpi ,
destinationPhone ,
esmClass ,
protocolId ,
priorityFlag ,
scheduledDeliveryTime ,
validityPeriodTime ,
new RegisteredDelivery() ,
ReplaceIfPresentFlag.DEFAULT.value() ,
new GeneralDataCoding(Alphabet.ALPHA_UCS2) ,
defaultMsgId ,
text.getBytes("ISO-10646-UCS-2") ,
optionalParameters.values().toArray(new OptionalParameter[0]));
return msgId;
}
}
Client code which invokes the service (it is actually a scheduler job):
#Autowired private MessageSendingService messageSendingService;
#Scheduled(cron)
public void execute() {
List<DomainObject> messages = repository.findMessages(pageable, config.getBatch()); //up to several thousand
start(messages);
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(getSchedulerConfiguration().getPoolSize(), new NamedThreadFactory("Factory"));
List<DomainObject> domainObjects = Collections.synchronizedList(messages);
List<List<DomainObject>> domainObjectsPartitioned = partition(domainObjects.size(), config.getPoolSize()); //pool size is 4
for (List<DomainObject> list: domainObjectsPartitioned ) {
executorService.execute(new Runnable() {
#Override
public void run() {
try {
start(list);
} catch (Exception e) {
e.printStackTrace();
}
});
}
executorService.shutdown();
}
}
private void start(List<DomainObject> list){
for (DomainObject> obj : list) {
String mid = messageSendingService.send(obj);
//do smtg with id...
}
}

Repository Returning Null while attempting Horizontal Scaling of a Service Class

[ISSUE] repo always returns null when I call repo methods, while stepping through, throws null pointer exception. then front end receives
500: Http failure response for http://localhost:4200/api/aiprollout/updatecsv: 500 Internal Server Error
[HAVE TRIED] Adjusting AutoWired and components and service annotations.
[QUESTIONS]
1- Does every repo method need its own service and controller method?
2- Is it okay to create a new service that uses an existing controller?
3- If this new service uses SuperCsv and I create custom CsvCellProcessors, can these cell processors also call the repo? Should these cell processors perform logic? or should it be done else where? What class annotations should these cellProcessors classes have? #Component?
Any advice is greatly appreciated, feel a little lost at this point not even sure what to do.
[CODE]
Controller:
#RestController
#EnableConfigurationProperties({SpoofingConfigurationProperties.class})
#RequestMapping(value = "")
public class AipRolloutController {
private final Logger logger = some logger
private final AipRolloutService AipRolloutService;
private final CsvParserService csvParserService;
#Autowired
public AipRolloutController(AipRolloutService aipRolloutService, CsvParserService csvParserService) {
this.AipRolloutService = aipRolloutService;
this.csvParserService = csvParserService;
}
#PostMapping(value = "/updatecsv", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<?> processCsv(#RequestParam("csvFile") MultipartFile csvFile) throws IOException {
if (csvFile.isEmpty()) return new ResponseEntity(
responceJson("please select a file!"),
HttpStatus.NO_CONTENT
);
csvParserService.parseCsvFile(csvFile);
return new ResponseEntity(
responceJson("Successfully uploaded - " + csvFile.getOriginalFilename()),
new HttpHeaders(),
HttpStatus.CREATED
);
}
Service:
#Service
public class AipRolloutService {
private static final Logger logger = some logger
#Autowired
private AIPRolloutRepository AIPRolloutRepository;
New Csv parser Service
#Service
public class CsvParserService {
#Autowired private AipRolloutService aipRolloutService;
public CsvParserService(AipRolloutService aipRolloutService) {
this.aipRolloutService = aipRolloutService;
}
public void parseCsvFile(MultipartFile csvFile) throws IOException {
CsvMapReader csvMapReader = new CsvMapReader(new InputStreamReader(csvFile.getInputStream()), CsvPreference.STANDARD_PREFERENCE);
parseCsv(csvMapReader);
csvMapReader.close();
}
private void parseCsv(CsvMapReader csvMapReader) throws IOException {
String[] header = csvMapReader.getHeader(true);
List<String> headers = Arrays.asList(header);
verifySourceColumn(headers);
verifyPovColumn(headers);
final CellProcessor[] processors = getProcessors(headers);
Map<String, Object> csvImportMap = null;
while ((csvImportMap = csvMapReader.read(header, processors)) != null) {
CsvImportDTO csvImportDto = new CsvImportDTO(csvImportMap);
if ( activationTypeP(csvImportDto) ){
int mssValue = Integer.parseInt(csvImportDto.getMssValue());
aipRolloutService.updateAipRollout(csvImportDto.getSource(),
csvImportDto.getPov(),
csvImportDto.getActivationType(),
mssValue);
}
}
}
private CellProcessor[] getProcessors(List<String> headers) {
CellProcessor[] processors = new CellProcessor[headers.size()];
int index = 0;
for (String header : headers) {
if (header.contains(SOURCE_ID)) {
processors[index++] = new CsvSourceIdCellParser();
} else if (header.contains(POV)) {
processors[index++] = new CsvPovCellParser();
} else if (header.contains(ACTIVATION_TYPE)) {
processors[index++] = new CsvActivationTypeCellParser();
} else if (header.contains(ACTIVATION_DATE)) {
processors[index++] = new Optional();
} else if (header.contains(DEACTIVATION_DATE)) {
processors[index++] = new Optional();
} else if (header.contains(MSS_VALUE)) {
processors[index++] = new CsvMssValueCellParser();
} else {
processors[index++] = null; // throw exception? wrong header info instead of allowing null?
}
}
return processors;
}
Custom Cell Processor that calls repo and returns null
public class CsvSourceIdCellParser extends CellProcessorAdaptor {
#Autowired AIPRolloutRepository aipRolloutRepository;
public CsvSourceIdCellParser(){ super(); }
// this constructor allows other processors to be chained
public CsvSourceIdCellParser(CellProcessor next){ super(next); }
#Override
public Object execute(Object value, CsvContext csvContext) {
// throws an Exception if the input is null
validateInputNotNull(value, csvContext);
// get rid of description only need first 3 #'s
value = value.toString().substring(0,3);
// check if WH exists
if( aipRolloutRepository.dcExistsInDatabase(value.toString()) )
return value;
else
throw new RuntimeException("Check Warehouse Value, Value Not Found "
+ "Row number: " + csvContext.getRowNumber()
+ " Column number: " + csvContext.getColumnNumber());
}
}
Repository
#Repository
public class AIPRolloutRepository {
private static final Logger logger = LoggerFactory.getLogger(AIPRolloutRepository.class);
#Autowired
JdbcTemplate jdbcTemplate;
public AIPRolloutRepository() {
}
public boolean dcExistsInDatabase(String dc){
// Query for a count saves time and memory, query for distinct saves time and memory on execution
boolean hasRecord =
jdbcTemplate
.query( "select count (distinct '" + dc +"')" +
"from xxcus.XX_AIP_ROLLOUT" +
"where DC = '" + dc + "';",
new Object[] { dc },
(ResultSet rs) -> {
if (rs.next()) {
return true;
}
return false;
}
);
return hasRecord;
}

How to filter events in Jersey SSE?

When i was looking examples of jersey sse i have found one example sse-item-store-webapp in jersey example folder. It is very simple app that has one input and one button. You type some text, click the button and other people get changes.
#Path("items")
public class ItemStoreResource {
private static final ReentrantReadWriteLock storeLock = new ReentrantReadWriteLock();
private static final LinkedList<String> itemStore = new LinkedList<String>();
private static final SseBroadcaster broadcaster = new SseBroadcaster();
private static volatile long reconnectDelay = 0;
#GET
#Produces(MediaType.TEXT_PLAIN)
public String listItems() {
try {
storeLock.readLock().lock();
return itemStore.toString();
} finally {
storeLock.readLock().unlock();
}
}
#GET
#Path("events")
#Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput itemEvents(#HeaderParam(SseFeature.LAST_EVENT_ID_HEADER) #DefaultValue("-1") int lastEventId) {
final EventOutput eventOutput = new EventOutput();
if (lastEventId >= 0) {
LOGGER.info("Received last event id :" + lastEventId);
// decide the reconnect handling strategy based on current reconnect delay value.
final long delay = reconnectDelay;
if (delay > 0) {
LOGGER.info("Non-zero reconnect delay [" + delay + "] - responding with HTTP 503.");
throw new ServiceUnavailableException(delay);
} else {
LOGGER.info("Zero reconnect delay - reconnecting.");
replayMissedEvents(lastEventId, eventOutput);
}
}
if (!broadcaster.add(eventOutput)) {
LOGGER.severe("!!! Unable to add new event output to the broadcaster !!!");
// let's try to force a 5s delayed client reconnect attempt
throw new ServiceUnavailableException(5L);
}
return eventOutput;
}
private void replayMissedEvents(final int lastEventId, final EventOutput eventOutput) {
try {
storeLock.readLock().lock();
final int firstUnreceived = lastEventId + 1;
final int missingCount = itemStore.size() - firstUnreceived;
if (missingCount > 0) {
LOGGER.info("Replaying events - starting with id " + firstUnreceived);
final ListIterator<String> it = itemStore.subList(firstUnreceived, itemStore.size()).listIterator();
while (it.hasNext()) {
eventOutput.write(createItemEvent(it.nextIndex() + firstUnreceived, it.next()));
}
} else {
LOGGER.info("No events to replay.");
}
} catch (IOException ex) {
throw new InternalServerErrorException("Error replaying missed events", ex);
} finally {
storeLock.readLock().unlock();
}
}
#POST
public void addItem(#FormParam("name") String name) {
// Ignore if the request was sent without name parameter.
if (name == null) {
return;
}
final int eventId;
try {
storeLock.writeLock().lock();
eventId = itemStore.size();
itemStore.add(name);
// Broadcasting an un-named event with the name of the newly added item in data
broadcaster.broadcast(createItemEvent(eventId, name));
// Broadcasting a named "size" event with the current size of the items collection in data
broadcaster.broadcast(new OutboundEvent.Builder().name("size").data(Integer.class, eventId + 1).build());
} finally {
storeLock.writeLock().unlock();
}
}
private OutboundEvent createItemEvent(final int eventId, final String name) {
Logger.getLogger(ItemStoreResource.class.getName()).info("Creating event id [" + eventId + "] name [" + name + "]");
return new OutboundEvent.Builder().id("" + eventId).data(String.class, name).build();
}
}
For example, if i have a chat rooms i don't understand how to implement that using SSE becouse every client connects to /items/events and if someone post new message to some chat broadcaster will broadcast this message to all signed events however i want broadcast events only for some chat.
Who works with Jersey SSE could you advise how to implement that ?
try to use smth like a map with chat room ids to SseBroadcast object, then you could subscribe all users from certain room to broadcaster. You may use that as for tet-a-tet conversations or team conversations.
Sample below:
private static final Map<Long, SseBroadcaster> ROOM_SSE_BROADCASTER = new ConcurrentHashMap<>();
#GET
#Path("/updatestate/{roomId}/{userId}")
#Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput updateState(#PathParam("roomId") Long roomId, #PathParam("userId") Long userId) {
EventOutput eo = new EventOutput();
ROOM_SSE_BROADCASTER.get(roomId).add(eo);
return eo;
}
public static void updateRoom(Long roomId) {
ROOM_SSE_BROADCASTER.get(roomId).broadcast(buildEvent());
}
public static void registerRoom(Long roomId) {
ROOM_SSE_BROADCASTER.put(roomId, new SseBroadcaster());
}
private static OutboundEvent buildEvent() {
OutboundEvent.Builder builder = new OutboundEvent.Builder();
OutboundEvent event = builder.data(String.class, "update").build();
return event;
}

Server returned HTTP response code: 403 for URL

I'm calling SAOP Webservice via a main method and it works fine.. But when i invoke the same method via a browser called method it give me the following error.
Caused by: java.io.IOException: Server returned HTTP response code: 403 for URL:
------------Working Code as Follows---------------------------
public class WSConnectionUtil {
private static final WSConnectionUtil INSTANCE = new WSConnectionUtil();
public SynchronizationServiceWSImpl getSyncServicePort(){
SynchronizationServiceWSImplService service = new SynchronizationServiceWSImplService();
SynchronizationServiceWSImpl servicePort = service.getSynchronizationServiceWSImplPort();
((BindingProvider) servicePort).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,getInstance().getSyncUrl());
return servicePort;
}
public static WSConnectionUtil getInstance() {
return INSTANCE;
}
private String getSyncUrl(){
String url = "http://10.2.241.33/synchronize?wsdl";
return url;
}
}
public void syncAll(){
System.out.println("===========syncAll======"+new Date());
SynchronizationRequest request = new SynchronizationRequest();
WSConnectionUtil wsCon = WSConnectionUtil.getInstance();
request.setPosCode("TNCB");
SynchronizationResponse response = wsCon.getSyncServicePort().synchronize(request);
List<String> types = response.getUpdateTypes();
System.out.println("===========types======"+types.size());
}
----------Error Code---------------------
/**
*
* service for login execution
* - user : Contains user id & password
* #param user
* #return
*
*/
#RequestMapping(value = "/login", method = RequestMethod.POST)
public #ResponseBody ModelMap login(#ModelAttribute ("User")User user ){
String username = user.getName();
String password = user.getPassword();
ModelMap model = new ModelMap();
Boolean status = loginService.login(username, password);
if(status == true){
model.put("status", true);
}
return model;
}
public boolean login(String loginUser,String password){
Steward steward = new Steward();
steward.setStewardId(Integer.parseInt(loginUser));
//List<Steward> stewardsList = stewardDao.getStewardsByCriteria(steward);
//if(stewardsList!=null && stewardsList.size()>0){
// steward = stewardsList.get(0);
//}else{
// LOG.error("Cannot Find a Steward for Login : "+loginUser);
// return false;
//}
TouchPosApplication.getApplication().setUser("SYSTEM");
TouchPosApplication.getApplication().setOutletCode("A");
TouchPosApplication.getApplication().setLoginUserId(loginUser);
// final SynchronizationServiceImpl impl = new SynchronizationServiceImpl();
// impl.syncAll();
new Thread(new Runnable() {
private static final long serialVersionUID = -4094418102152819603L;
#Override
public void run() {
while (true) {
long i =0;
try {
i = 1000 * 60 * 1;
Thread.sleep(i);
} catch (InterruptedException e) {
System.out.println("===InterruptedException==========="+e);
}
SyncUtil.synchronizeAutomatic(true);
}
}
}).start();
LOG.info("::::: Successfuly Logged In :"+loginUser);
return true;
}

thread.run() works and thread.start() not works

Following is my main class.
public class ShareData {
/**
* #param args
*/
public static void main(String[] args) {
ShareReader aShareReader = new ShareReader("http://test.com:9000", "dilip.id#gmail.com", "password");
Thread fileThread = new Thread(aShareReader);
fileThread.run(); // fileThread.start() not calling the run() method
}
}
If I type fileThread.run() run method is called. If I call fileThread.start() the run metod is not called. Following is my thread class. I dont know what I am doing wrong.
public class ShareReader implements Runnable {
private String itsShareURL = null;
private String itsUserId = null;
private String itsPassword = null;
private String itsAuthToken = null;
private String itsLoginURL = null;
private String itsChannelUpateURL = null;
/**
*
*/
public ShareReader(String theShareURL, String theUserId, String thePassword) {
this.itsShareURL = theShareURL;
this.itsUserId = theUserId;
this.itsPassword = thePassword;
this.itsLoginURL = itsShareURL + "/v1.0-SNAPSHOT/login";
this.itsChannelUpateURL = itsShareURL + "/v1.0-SNAPSHOT/updateChannelSubscription/";
}
public void run() {
JSONObject json;
JSONArray jsonArray;
itsAuthToken = getToken(itsUserId, itsPassword);
updateChannelList(itsAuthToken);
String aURL = "http://test.com:9000/v1.0-SNAPSHOT/userTimeline/"+itsAuthToken+"/";
try {
String lat = null;
String lon = null;
String udid = null;
String dateTime = null;
String eventID = null;
aEventBean = new EventBean();
jsonArray = readJsonArrayFromUrl(aURL);
for (int i = 0; i < jsonArray.length(); i++) {
json = jsonArray.getJSONObject(i);
lat = json.getString("lat");
lon = json.getString("lon");
udid = json.getString("udid");
eventID = json.getString("eventId");
dateTime = json.getString("dateTime");
aEventBean.setItsLatitude(lat);
aEventBean.setItsLongitude(lon);
aEventBean.setItsUDID(udid);
aEventBean.setItsEventIdentifier(eventID);
aEventBean.setItsDateTime(dateTime);
System.out.println(udid + " ---> " +lat + " ==== " + lon);
sendData(aEventBean);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Sorry If I ask so basic question..
Ideally I need to do fileThread.start() to start a thread..
Thanks in advance...
run() is definitely called if you call start() on fileThread. Check your implementation of run()- its very likely that this method completes or terminates before your check for the print statements. Just an fyi, fileThread.run() is a sequential call while fileThread.start() is a parallel call.
Another vague possibility is that you're not implementing Java's runnable; instead, that may be some custom Runnable class in your project.
EDIT:
So apparently calling fileThread.join() helped you fix your problem, but why does this work? If you call fileThread.join(), the main thread waits until the target (in this case, your fileThread object) terminates.
fileThread.run() never starts a new thread. To start a new thread you have to call fileThread.start().

Categories