package com.voxeo.moho.reg.impl; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Map; import com.voxeo.moho.Endpoint; import com.voxeo.moho.event.AcceptableEvent.Reason; import com.voxeo.moho.event.RegisterEvent; import com.voxeo.moho.event.RegisterEvent.Contact; import com.voxeo.moho.reg.Registrar; import com.voxeo.moho.reg.RegistrarController; import com.voxeo.moho.reg.RegistrarStore; import com.voxeo.moho.reg.impl.mem.MemoryRegistrarStore; import com.voxeo.moho.sip.SIPRegisterEvent; import com.voxeo.moho.sip.SIPRegisterEvent.SIPContact; import com.voxeo.moho.sip.SIPRegisterEventImpl.ContactImpl; import com.voxeo.moho.spi.ExecutionContext; public class RegistrarImpl implements Registrar, Runnable { protected RegistrarStore _store; protected Collection<RegistrarController> _controllers = new ArrayList<RegistrarController>(); protected int _maxExpiration = 60000; protected Map<String, String> _props; protected boolean _running = false; protected Thread _runner; @Override public void doRegister(RegisterEvent event) { if (event instanceof SIPRegisterEvent) { doSIPRegister((SIPRegisterEvent) event); } else { event.reject(Reason.DECLINE); } } protected boolean isResponsibleFor(SIPRegisterEvent event) { // TODO check domains. return true; } protected void doSIPRegister(SIPRegisterEvent event) { // TODO: validate Required header if (isResponsibleFor(event)) { _store.startTx(); try { for (Contact contact : event.getContacts()) { if (contact.getExpiration() > _maxExpiration) { ((ContactImpl) contact).setExpiration(_maxExpiration); } if (!contact.isWildCard()) { Contact current = _store.getContact(event.getEndpoint(), contact.getEndpoint()); if (current != null && current instanceof SIPContact) { validateContact((SIPContact) contact, (SIPContact) current); if (contact.getExpiration() != 0) { _store.update(event.getEndpoint(), contact); } else { _store.remove(event.getEndpoint(), contact); } } else { _store.add(event.getEndpoint(), contact); } } else if (contact.getExpiration() == 0) { _store.remove(event.getEndpoint()); } } _store.commitTx(); event.accept(); } catch (Throwable t) { _store.rollbackTx(); event.reject(Reason.ERROR); } } else { // TODO proxy } } protected void validateContact(SIPContact newC, SIPContact currentC) { if (newC.getCallID() != currentC.getCallID()) { throw new IllegalArgumentException("Same contact can not be registered with different Call-ID."); } if (newC.getCSeq() < currentC.getCSeq()) { throw new IllegalArgumentException("Same contact can not be registered out of sequence."); } } @Override public Collection<Contact> getContacts(Endpoint aor) { return _store.getContacts(aor); } @Override public void addController(RegistrarController controller) { _controllers.add(controller); } @Override public void removeController(RegistrarController controller) { _controllers.remove(controller); } @Override public Iterator<RegistrarController> getControllers() { return _controllers.iterator(); } @Override public void run() { while (_running) { Iterator<Endpoint> i = _store.getEndpoints(); Endpoint ep = null; while (_running && i.hasNext()) { ep = i.next(); try { _store.startTx(); Collection<Contact> contacts = _store.getContacts(ep); for (Contact contact : contacts) { if (contact.isExpired()) { _store.remove(ep, contact); } } _store.commitTx(); } catch (Throwable t) { _store.rollbackTx(); } Thread.yield(); } try { Thread.sleep(_maxExpiration); } catch (Exception e) { // ignore } } } @Override public void init(ExecutionContext context, Map<String, String> props) { _props = props; String storeImpl = props.get(STORE_IMPL); if (storeImpl == null) { storeImpl = MemoryRegistrarStore.class.getName(); } try { _store = (RegistrarStore) Class.forName(storeImpl).newInstance(); _store.init(props); } catch (Exception e) { throw new IllegalArgumentException("Invalidate Registrar Store implementation: " + e); } String max = props.get(MAX_EXPIRE); if (max != null) { this._maxExpiration = Integer.parseInt(max); } // TODO: get all the domains. _running = true; _runner = new Thread(this, "Registrar"); _runner.setDaemon(true); _runner.start(); } @Override public void destroy() { _running = false; _runner.interrupt(); _store.destroy(); } @Override public String getName() { return Registrar.class.getName(); } }