Статьи

Гобелен Магия: интеграция с комет

Каждый раз, когда я работаю с Tapestry, мне интересно, как люди могут использовать Java, а не использовать Tapestry. Это так весело, но ведь не все хотят получать удовольствие от работы !! Недавно был опубликован файл jira для интеграции с cometd-java . Я никогда не использовал Cometd, но думал попробовать. Интеграция была простой, но тестирование с использованием gradle и eclipse было головной болью и занимало большую часть моего воскресенья.

Эта интеграция позволит вам выставить сервисы комет от Tapestry. Эти сервисы не будут сервисами Tapestry-ioc, но смогут получить доступ к любым сервисам или объектам Tapestry-ioc, используя @Inject и co. аннотаций.

Cometd-java использует сервлеты для инициализации и предоставления своих сервисов. Я разделил две работы. Инициализация BayeuxServer выполняется BayeuxServiceSource, а службы предоставляются CometdRequestFilter, реализацией HttpServletRequestFilter. Приведенный ниже код является просто копией- вставкой, взятой из CometdServlet.java и AnnotationCometdServlet.java.

Сначала простая часть, CometdRequestFilter

public class CometdRequestFilter implements HttpServletRequestFilter {

private BayeuxServerSource bayeuxServerSource;
private String path;
private Logger logger;

public CometdRequestFilter(BayeuxServerSource bayeuxServerSource,
RequestGlobals requestGlobals, Logger logger,
@Symbol(CometdConstants.CONTEXT_PATH) @Inject String path) {
this.bayeuxServerSource = bayeuxServerSource;
this.path = path.toLowerCase();
this.logger = logger;

try {
bayeuxServerSource.startServer();
logger.debug("Allowed protocols are : " + bayeuxServerSource.getAllowedTransports());
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Could not start Bayeux Server: "
+ e.getMessage(), e);
}
}

private void setServiceOptions(HttpServletRequest request,
HttpServletResponse response) {

}

public boolean service(HttpServletRequest request,
HttpServletResponse response, HttpServletRequestHandler handler)
throws IOException {
//Not my path, so don't handle it
if (!request.getRequestURI().startsWith(request.getContextPath() + path)) {
logger.debug("Skipping " + request.getRequestURI() + " not matching "
+ path);
return handler.service(request, response);
}

logger.debug("Processing request : " + request.getRequestURI());
if ("OPTIONS".equals(request.getMethod())) {
setServiceOptions(request, response);
return true;
}

HttpTransport transport = null;

for (HttpTransport allowedTransport : bayeuxServerSource.getAllowedTransports()) {
if (allowedTransport != null && allowedTransport.accept(request)) {
transport = allowedTransport;
break;
}
}

if (transport == null) {
logger.error("Request " + request.getRequestURI()
+ " Unknown Bayeux Transport");
response.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Unknown Bayeux Transport");
} else {
BayeuxServerImpl bayeux = bayeuxServerSource.getBayeuxImpl();
try {
bayeux.setCurrentTransport(transport);
transport.setCurrentRequest(request);
transport.handle(request, response);
} catch (ServletException e) {
throw new IOException(e);
} finally {
transport.setCurrentRequest(null);
if (bayeux != null) {
bayeux.setCurrentTransport(null);
}
}
}

return true;
}

}

Этот фильтр используется для перехвата всех запросов, и если запрос относится к нашему подконтексту / пути, мы рассматриваем его как запрос cometd, в противном случае мы просим оставшуюся цепочку обработать его. В конструкторе запускаем сервер. Нам не нужно беспокоиться об очистке, так как она выполняется самой службой.

При обработке запроса в методе service () мы проверяем, является ли это разрешенным типом транспорта, и в случае, если это так, мы просим транспорт обработать запрос. Подробная информация о сервере Bayeux находится в BayeuxServerSource.

public interface BayeuxServerSource {

BayeuxServer getBayeux();

BayeuxServerImpl getBayeuxImpl();

List<HttpTransport> getAllowedTransports();

void startServer();
public interface BayeuxServerSource {

BayeuxServer getBayeux();

BayeuxServerImpl getBayeuxImpl();

List<HttpTransport> getAllowedTransports();

void startServer();
}}

Реализация bayeux представлена ​​здесь так, как этого требует фильтр. Сервис BayeuxServerSource реализован как

public class BayeuxServerSourceImpl implements BayeuxServerSource,
RegistryShutdownListener {

private BayeuxServerImpl bayeux;

private List<HttpTransport> allowedTransports;

private List<Object> annotationServices;

private ServerAnnotationProcessor annotationProcessor;

private ObjectLocator locator;

private List<BayeuxServerConfigurer> configurers;

private Logger logger;

private boolean initialized;

public BayeuxServerSourceImpl(List<BayeuxServerConfigurer> configurers,
ObjectLocator locator, Logger logger) {
bayeux = newBayeuxServer();
this.locator = locator;
this.configurers = configurers;
this.logger = logger;
annotationServices = new ArrayList<Object>();
allowedTransports = new ArrayList<HttpTransport>();
initialized = false;
}

public synchronized void startServer(){
if(initialized){
throw new RuntimeException("The Bayeux Server is already started");
}

List<Class<?>> annotationServiceClasses = new ArrayList<Class<?>>();
logger.debug("Configuring Bayeux Server using configurers");
for(final BayeuxServerConfigurer configurer: configurers){
configurer.configure(bayeux, annotationServiceClasses);
}

try {
logger.debug("Starting server");
bayeux.start();
} catch (Exception e) {
throw new RuntimeException(e);
}

addAllowedTransports();

setupAnnotatedServices(annotationServiceClasses);

initialized = true;
}

private void addAllowedTransports() {
logger.debug("Adding allowed transports");
for (String transportName : bayeux.getAllowedTransports()) {
ServerTransport transport = bayeux.getTransport(transportName);
if (transport instanceof HttpTransport) {
logger.debug("Adding transport " + transportName);
allowedTransports.add((HttpTransport) transport);
}
}
}

private void setupAnnotatedServices(List<Class<?>> annotationServiceClasses) {
logger.debug("Setting annotation services processor");
annotationProcessor = new ServerAnnotationProcessor(getBayeux());

for (Class<?> service : annotationServiceClasses) {
Object object = locator.autobuild(service);
logger.info("Building service for interface " + service);
annotationProcessor.process(object);
annotationServices.add(object);
}
}

protected BayeuxServerImpl newBayeuxServer() {
return new BayeuxServerImpl();
}

public BayeuxServer getBayeux() {
return bayeux;
}

public BayeuxServerImpl getBayeuxImpl() {
return bayeux;
}

public List<HttpTransport> getAllowedTransports() {
return allowedTransports;
}

public void registryDidShutdown() {
if (!initialized) {
return;
}
cleanupAnnotatedServices();
cleanupSessions();

try {
bayeux.stop();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
bayeux = null;
}

allowedTransports.clear();
}

private void cleanupAnnotatedServices() {
if (annotationProcessor != null) {
for (Object service : annotationServices) {
logger.debug("Deprocessing " + service);
annotationProcessor.deprocess(service);
}
}
}

private void cleanupSessions() {
for (ServerSession session : bayeux.getSessions()) {
logger.debug("Cleaning up session : " + session);
((ServerSessionImpl) session).cancelSchedule();
}

}
}

Это просто запуск и очистка сервиса. Поддержка комментирования Cometd также была включена. Единственная магия со стороны Tapestry — ObjectLocator.autobuild (). Этот метод выполняет всю работу по внедрению и дает нам экземпляр, который затем передается в ServerAnnotationProvider компании cometd для дальнейшей обработки.

Вклад / инициализация в BayeuxServerSource производится через BayeuxServerConfigurer.

public interface BayeuxServerConfigurer {
void configure(BayeuxServerImpl bayeuxServerImpl, List<Class<?>> annotatedServices);
}

Наконец, файл модуля

public class TapestryCometdModule {

public BayeuxServerSource buildBayeuxServerSource(
List<BayeuxServerConfigurer> configurers, ObjectLocator locator,
Logger logger,
RegistryShutdownHub registryShutdownHub) {
BayeuxServerSourceImpl impl = new BayeuxServerSourceImpl(configurers, locator, logger);
registryShutdownHub.addRegistryShutdownListener(impl);
return impl;
}

public static void contributeHttpServletRequestHandler(
OrderedConfiguration<HttpServletRequestFilter> filters) {
filters.addInstance("Cometd", CometdRequestFilter.class);
}

public BayeuxServer buildBayeuxServer(BayeuxServerSource bayeuxServerSource,
PropertyShadowBuilder shadowBuilder) {
return shadowBuilder.build(bayeuxServerSource, "bayeux",
BayeuxServer.class);
}

public static void contributeFactoryDefaults(
MappedConfiguration<String, String> configuration) {
configuration.add(CometdConstants.CONTEXT_PATH, "/cometd/");
}

}

Здесь ничего особенного не происходит, мы создаем экземпляр BayeuxServerSource, передаем его в RegistryShutdownHub для правильной очистки и выставляем два его метода в качестве сервисов, используя ShadowBuilder.

Вы можете найти исходный код вместе с тестами здесь

 

От http://tawus.wordpress.com/2011/06/13/tapestry-magic-15-integration-with-cometd/