Каждый раз, когда я работаю с 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/