30. januar 2004 - 15:12Der er
11 kommentarer og 1 løsning
Notify ser ikke ud til at blive kaldt
Jeg har en metode (waitGetEvent), som skal returnere når en event opstår eller efter et bestemt stykke tid (waitTime) Til det brug anvender jeg wait(waitTime) og notify. Min wait timer pænt ud når tiden er gået, men wait afbrydes aldrig af notify, selv om der kommer en event før tiden udløber.
Det ser nærmest ud som om metoderne blokerer for hinanden.
public class Connection extends Thread implements ConnectionObserver { private int Handle; private SoftPhone sp; private Hashtable monitors; private ConnectionState state; private ArrayList events; private Logger log = Logger.getLogger(Connection.class); Object lock = new Object();
public Connection() { Handle = this.hashCode(); events = new ArrayList (); monitors = new Hashtable(); setState(new ConnectionIDLEFactoryFunctor()); } private synchronized void setState(ConnectionStateFactoryFunctor factory) { ConnectionStateWrapper.setFactory(factory); state = ConnectionStateWrapper.instance(); } /** * Returns the handle for the connection. * * @return Handle * @see Connection#getHandle */ public int getHandle() { return Handle; } /** * Returns the a Monitor object for the DN * * @return Monitor * @see Connection#getMonitor */ public Monitor getMonitor(String DN) { return (Monitor)monitors.get(DN); } /** * Execute an 'Open' request. * to get a Connection to the PBX. * @return Result parameter * @see Connection#open */ public int open() throws MethodNotAvailableInStateException { int res; try { sp = new SoftPhone(); sp.addObserver(this); res = state.open(sp); } catch (MethodNotAvailableInStateException ex) { throw ex; } catch (Exception e) { // Den aktive instance er ikke OK, sørg for at en ny trækkes næste gang ConnectionStateWrapper.setInstance(null); setState(new ConnectionIDLEFactoryFunctor()); res = state.open(sp); } if (res == 0) setState(new ConnectionCONNECTEDFactoryFunctor()); else setState(new ConnectionDISCONNECTEDFactoryFunctor()); return res; } public int open(String ip,String user, String pw) throws MethodNotAvailableInStateException { int res; try { sp = new SoftPhone(); sp.addObserver(this); res = state.open(sp, ip, user, pw); } catch (MethodNotAvailableInStateException ex) { throw ex; } catch (Exception e) { // Den aktive instance er ikke OK, sørg for at en ny trækkes næste gang ConnectionStateWrapper.setInstance(null); setState(new ConnectionIDLEFactoryFunctor()); res = state.open(sp, ip, user, pw); } if (res == 0) setState(new ConnectionCONNECTEDFactoryFunctor()); else setState(new ConnectionDISCONNECTEDFactoryFunctor()); return res; } /** * Execute an 'Close' request. * to get a Connection to the PBX. * @return Result parameter * @see Connection#close */ public int close() throws MethodNotAvailableInStateException { try { if ( state.close(sp) == 0) return cleanUp(); return 9999; } catch (MethodNotAvailableInStateException ex) { throw ex; } catch (Exception e) { return 9999; } } private int cleanUp() { Monitor mon; try { Enumeration enum = monitors.elements(); while(enum.hasMoreElements()) { mon = (Monitor)enum.nextElement(); removeMonitor(mon.getDN()); } setState(new ConnectionDISCONNECTEDFactoryFunctor()); return 0; } catch (Exception e) { log.error("CleanUp: ", e); return 9999; } } /** * Returns the state for connection * * @return Monitor * @see Connection#getState */ public String getState() { return state.getState(); } /** * Adds a Monitor object to the connection * * @return int * @see Connection#addMonitor */ public int addMonitor(String DN) throws MethodNotAvailableInStateException { int res; Monitor mon = new Monitor(DN,this); try { res = state.addMonitor(sp,mon); } catch (MethodNotAvailableInStateException ex) { throw ex; } catch (Exception e) { // Den aktive instance er ikke OK, sørg for at en ny trækkes næste gang ConnectionStateWrapper.setInstance(null); setState(new ConnectionIDLEFactoryFunctor()); res = state.addMonitor(sp,mon); } if (res == 0) { sp.addMonitorObserver(mon); sp.getCMConnection(DN).addObserver(mon); monitors.put(DN,mon); } return res; } /** * Removes the Monitor object from the connection * * @return int * @see Connection#removeMonitor */ public int removeMonitor(String DN) throws MethodNotAvailableInStateException { int res; Monitor mon = (Monitor)monitors.get(DN); if (mon == null) { log.error("Monitor: " + DN + " not found"); return 9999; } try { mon.stopMonitor(); res = state.removeMonitor(sp,mon);
} catch (MethodNotAvailableInStateException ex) { throw ex; } catch (Exception e) { // Den aktive instance er ikke OK, sørg for at en ny trækkes næste gang ConnectionStateWrapper.setInstance(null); setState(new ConnectionIDLEFactoryFunctor()); res = state.removeMonitor(sp,mon); } if (res == 0) { sp.removeMonitorObserver(mon); if (monitors.containsKey(DN)) monitors.remove(DN); } return res; } /** * Make a call on the monitor for the DN * * @return int * @see Connection#Makecall */ public int makeCall(String DN, String calledNo) throws MethodNotAvailableInStateException { int res; Monitor mon = (Monitor)monitors.get(DN); if (mon == null) { log.error("Monitor: " + DN + " not found"); return 9999; } try { if (mon.makeCall()) { mon.addCall(state.makeCall(sp,mon, calledNo)); return 0; } return 9999; } catch (MethodNotAvailableInStateException ex) { throw ex; } catch (Exception e) { log.error("makeCall: ", e); return 9999; } } /** * Hang up a call on the monitor for the DN * * @return int * @see Connection#Hangup */ public int hangup(String DN, String refid) throws MethodNotAvailableInStateException { int res; Monitor mon = (Monitor)monitors.get(DN); if (mon == null) { log.error("Monitor: " + DN + " not found"); return 9999; } try { if (mon.hangup(refid)) { return state.hangup(sp,mon, refid); } return 9999; } catch (MethodNotAvailableInStateException ex) { throw ex; } catch (Exception e) { log.error("hangup: ", e); return 9999; } } /** * Answer incoming call on the DN * @return int * @see Connection#Answer */ public int answer(String DN) throws MethodNotAvailableInStateException { int res; Monitor mon = (Monitor)monitors.get(DN); if (mon == null) { log.error("Monitor: " + DN + " not found"); return 9999; } try { if (mon.answer()) { return state.answer(sp,mon); } return 9999; } catch (MethodNotAvailableInStateException ex) { throw ex; } catch (Exception e) { log.error("answer: ", e); return 9999; } } /** * Retreive call with refid on the DN * @return int * @see Connection#retreive */ public int retreive(String DN, String refId) throws MethodNotAvailableInStateException { int res; Monitor mon = (Monitor)monitors.get(DN); if (mon == null) { log.error("Monitor: " + DN + " not found"); return 9999; } try { if (mon.retreive(refId)) { return state.retreive(sp,mon, refId); } return 9999; } catch (MethodNotAvailableInStateException ex) { throw ex; } catch (Exception e) { log.error("retreive: ", e); return 9999; } } /** * Making a consultation with another DN while having an held call on the other * @return int * @see Connection#consultation */ public String[] consultation(String DN,String consultNo) throws MethodNotAvailableInStateException { int res; String oldRefId; String newRefId; Monitor mon = (Monitor)monitors.get(DN); if (mon == null) { log.error("Monitor: " + DN + " not found"); return null; } try { oldRefId = mon.consultation(); if (oldRefId != null) { newRefId = mon.addCall(state.consultation(sp,mon, consultNo)); return new String [] {oldRefId,newRefId}; } return null; } catch (MethodNotAvailableInStateException ex) { throw ex; } catch (Exception e) { log.error("consult: ", e); return null; } } /** * Transferring call on the DN to another DN * @return int * @see Connection#transfer */ public int transfer(String DN,String heldRefId, String newRefId) throws MethodNotAvailableInStateException { int res; Monitor mon = (Monitor)monitors.get(DN); if (mon == null) { log.error("Monitor: " + DN + " not found"); return 9999; } try { if (mon.transfer()) { state.transfer(sp,mon, heldRefId,newRefId); return 0; } return 9999; } catch (MethodNotAvailableInStateException ex) { throw ex; } catch (Exception e) { log.error("transfer: ", e); return 9999; } } public void ConnectionChangedEvent(ConnectionEv event) { try { switch (event.getCode()) { case 0: close(); setState(new ConnectionDISCONNECTEDFactoryFunctor()); System.out.println("STARTERROR"); break; case 1: if (state instanceof ConnectionCONNECTED) break; else setState(new ConnectionCONNECTEDFactoryFunctor()); System.out.println("STARTUP"); break; case 2: cleanUp(); setState(new ConnectionDISCONNECTEDFactoryFunctor()); System.out.println("STOP"); break; case 17: close(); setState(new ConnectionDISCONNECTEDFactoryFunctor()); System.out.println("FATALERROR"); break; } events.add(event); synchronized(lock) { log.debug("i notify delen"); lock.notify(); } } catch (Exception e) { events.add(new ConnectionEv(17,"FATALERROR")); log.error("Error in connectioneventchanged: " + e.toString()); } } public ConnectionEv getEvent() { try { if (events.size ()== 0) return null; ConnectionEv event = (ConnectionEv)events.get(0); events.remove(0); return event; } catch (Exception e) { log.error("Error in getevent: "+ e.toString()); return null; } } public ConnectionEv waitGetEvent(int waitTime) { try { ConnectionEv ev = getEvent(); if (ev != null) return ev; GetEventThread waitThread = new GetEventThread(waitTime); waitThread.run(); /* try { synchronized(lock) { lock.wait(waitTime); log.debug("Interrupted by time"); } } catch (InterruptedException ex) { log.debug("Interrupted by event"); return null; }
*/ return getEvent(); } catch (Exception e) { return new ConnectionEv(9999, new String(e.toString())); } } public void run() { } public void shutDown() { } protected void setEvent(ConnectionEv event) { events.add(event); } public static void main(String[] args) { Connection connection1 = new Connection(); ConnectionEv event; try { connection1.open(); System.out.println("Connected OK"); connection1.addMonitor("260"); } catch (Exception e) { System.out.println("Error in open: " + e.toString()); } } class GetEventThread extends Thread { int _waitTime; GetEventThread (int waitTime) { _waitTime = waitTime; } public void run() { try { synchronized(lock) { lock.wait(_waitTime); log.debug("Interrupted by time"); } } catch (InterruptedException e) { log.debug("Interrupted by notify"); } } } } nogen forslag til hvad der er galt ?
Manuelle og semi-automatiske strategier for identitetsstyring virker - lige indtil nogen beder om dokumentation. For at undgå denne fare har DKTV taget kontrol over sin identitets- og adgangsstrategi.
synchronized(lock) { lock.wait(_waitTime); log.debug("Interrupted by time"); } } catch (InterruptedException e) { log.debug("Interrupted by notify"); }
- ovenstående fungerer ikke efter hensigten - notify() resulterer ikke i en InterruptedException (prøv interrupt() i stedet.) Nedenstående skulle give mere mening:
synchronized(lock) { lock.wait(_waitTime); log.debug("Interrupted by time or notify"); } } catch (InterruptedException e) { log.debug("Possibly interrupted by interrupt"); }
OK. Jeg er egentlig ligeglad med årsag til at min wait bliver afbrudt, problemet er at den altid "løber tiden ud", selv om der kommer en event i mellemtiden, derfor tilbage til mit spørgsmål, hvorfor bliver notify ikke kaldt ? Er det fordi min wait låser monitoren ? Og hvis det er tilfældet hvordan undgår jeg det så ?
Det ved jeg fordi, jeg har testet det med en timeren sat til 10 sekunder. Klassen er en del af en program der styrer en IP-telefon og testen går ud på at jeg kalder waitgetevent(10000) og så løfter røret af inden de 10 sekunder er gået, men jeg får først at vide at det er sket 10 sekunder efter jeg kaldte metoden.
Connection-klassen implementerer et interface ConnectionObserver, som er en listener,der kaldes via callback (af connectionChanegedEvent)fra en anden klasse (SoftPhone), når der kommer connection events. I callbacken sendes en connection event med som parameter, hvis det er det du mener med output.
Jeg modtager denne event, men først efter at min wait er timet ud. Så den del af koden fungerer, men altså først når der er ventet 10 sek. i dette tilfælde.
Jeg kan ikke overskue om der er tale om samme tråd eller ej. Connection er observer til SoftPhone med har også en reference til SoftPhone objectet.
Det hjælper ikke at kalde start istedet for run enten returneres med det samme eller hvis koden flyttes fra run til start samme resultat som når run kaldes.
Der er ingen synkronisering omkring kaldet af waitgetevent.
Her er koden til SoftPhone, hvis der kan giv et praj om om der er tale om en eller flere tråde: package dk.sysint.tlink.callmanagergw; import java.util.ArrayList; import java.util.Iterator; import java.util.Vector;
Hvorvidt der er tale om samme tråd eller ej, kan du finde ud af ved at printe tråden ud på udvalgte steder, bare indsæt
System.out.println( Thread.currentThread() );
- du kan indsætte øverst i ConnectionChangedEvent() og waitGetEvent() metoderne. Hvis det er samme tråd, er det fejlen, ellers har jeg vist ikke flere bud. De 2 tråde _kunne_ også vente på samme monitor, men det er sikkert ikke dét..)
Du havde ret i at det var samme tråd. Hvis jeg anvender start() i stedet for run(), får jeg startet en ny tråde, men så kører waitGetEvent bare videre og jeg får ikke ventet.
Jeg har derfor opgivet at anvende wait/notify til dette og er gået over til en høkerløsning, som virker men ikke er så pæn: while (events.size() == 0 && waitTime > 0) { yield(); sleep(50); waitTime -= 50; } Selv om jeg ikke fik, den løsning jeg havde håbet på, har du besvaret spøgsmålet, så smid lige et svar og pointene er dine.
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.