From ee8de8c6b0e0aea8f9d2f8afdee22239c5d1f660 Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Thu, 11 Oct 2012 12:33:38 -0400 Subject: [PATCH] INTSAMPLES-95 Add Remote Monitor INTSAMPLES-95 Add OperationInvokingAdapter For reference see: https://jira.springsource.org/browse/INTSAMPLES-95 --- intermediate/monitoring/README.md | 35 ++- .../integration/model/TwitterMessage.java | 202 +++++++++--------- .../mvc/controller/HomeController.java | 94 ++++---- .../integration/service/TwitterService.java | 20 +- .../service/impl/DummyTwitter.java | 2 +- .../NotificationListener.java | 44 ++++ .../integration/remote-monitor-context.xml | 63 ++++++ .../spring-integration-context.xml | 19 +- .../META-INF/spring/mvc/servlet-context.xml | 53 ++--- .../monitoring/src/main/resources/log4j.xml | 2 +- .../integration/SpringIntegrationTest.java | 11 +- 11 files changed, 346 insertions(+), 199 deletions(-) create mode 100644 intermediate/monitoring/src/main/java/org/springintegration/NotificationListener.java create mode 100644 intermediate/monitoring/src/main/resources/META-INF/spring/integration/remote-monitor-context.xml diff --git a/intermediate/monitoring/README.md b/intermediate/monitoring/README.md index a780fffd..0d40a230 100644 --- a/intermediate/monitoring/README.md +++ b/intermediate/monitoring/README.md @@ -5,21 +5,39 @@ This application demonstrates managing and monitoring Spring Integration Applica It is based on the STS 'Spring Integration Project (war)' template project, available using -New... | Spring Template Project + New... | Spring Template Project -It was used in the "Managing and Monitoring Spring Integration" webinar available -on the SpringSource Developer YouTube Channel http://www.youtube.com/SpringSourceDev +It was used in the **Managing and Monitoring Spring Integration** webinar available on the [SpringSource Developer YouTube Channel][]. If you wish to see the changes made during the webinar, please use the following git command: -git log -p <The commit titled 'Webinar End State'> + git log -p -To run the sample, in STS, use Run As... | Run on Server +To run the sample, in STS, use: -and then use VisualVM/JConsole to explore the MBeans. + Run As... | Run on Server -The twitter search results can be examined at http://localhost:8080/monitoring +and then use [VisualVM][]/JConsole to explore the [MBeans][]. + +The twitter search results can be examined at `http://localhost:8080/monitoring`. + +## 2.2 Updates: + +The application context now includes an example of <int-jmx:notification-publishing-channel-adapter/>, to which the tweets are published. You can navigate to the MBean - **spring.application:type=TweetPublisher,name=tweeter**, click the _Notifications_ tab and then subscribe. You will then see the notifications. + +An additional class _NotificationListener_ is now included. It demonstrates the use of <int-jmx:notification-listening-channel-adapter> and <int-jmx:attribute-polling-channel-adapter>. + +Also, it shows how to use an <int-jmx:operation-invoking-channel-adapter> to stop/start the +_dummyAdapter_ in the web application. + +These adapters use a client connector to connect to the Twitter search web application to catch notifications published by it, polls the _sendCount_ attribute of the _twitterChannel_. and invokes operations on the _dummyAdapter_. + +You will need to update the credentials on the _clientConnector_ in _remote-monitor-context.xml_ to match your environment. If you are using STS, you can find the credentials in _Servers | [server] | jmxremote.password_. You can then run the _NotificationListener_'s main method. + +You should observe log output of the notifications as well as polling the channel's _sendCount_. Simply use the console to enter 'n' to stop and 'y' to start the adapter. + +These changes show how you can create a sophisticated monitoring application using Spring Integration - it is important to understand that the application being monitored doesn't have to be a Spring or Spring Integration application - any application that exports MBeans can be monitored in this way. -------------------------------------------------------------------------------- @@ -27,3 +45,6 @@ For help please see the Spring Integration documentation: http://www.springsource.org/spring-integration +[MBeans]: http://docs.oracle.com/javase/tutorial/jmx/mbeans/index.html +[SpringSource Developer YouTube Channel]: http://www.youtube.com/SpringSourceDev +[VisualVM]: http://visualvm.java.net/ diff --git a/intermediate/monitoring/src/main/java/org/springframework/integration/model/TwitterMessage.java b/intermediate/monitoring/src/main/java/org/springframework/integration/model/TwitterMessage.java index f287e69e..3c1b25fd 100644 --- a/intermediate/monitoring/src/main/java/org/springframework/integration/model/TwitterMessage.java +++ b/intermediate/monitoring/src/main/java/org/springframework/integration/model/TwitterMessage.java @@ -1,17 +1,17 @@ /* - * Copyright 2002-2010 the original author or authors + * Copyright 2002-2012 the original author or authors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.springframework.integration.model; @@ -22,109 +22,109 @@ import java.util.Date; */ public class TwitterMessage { - private Date createdAt; - private String text; - private String fromUser; - private String profileImageUrl; + private Date createdAt; + private String text; + private String fromUser; + private String profileImageUrl; - /** Default constructor. */ - public TwitterMessage() { - super(); - } + /** Default constructor. */ + public TwitterMessage() { + super(); + } - /** Constructor to initialize all fields available. */ - public TwitterMessage(Date createdAt, String text, String fromUser, - String profileImageUrl) { - super(); - this.createdAt = createdAt; - this.text = text; - this.fromUser = fromUser; - this.profileImageUrl = profileImageUrl; - } + /** Constructor to initialize all fields available. */ + public TwitterMessage(Date createdAt, String text, String fromUser, + String profileImageUrl) { + super(); + this.createdAt = createdAt; + this.text = text; + this.fromUser = fromUser; + this.profileImageUrl = profileImageUrl; + } - public Date getCreatedAt() { - return createdAt; - } + public Date getCreatedAt() { + return createdAt; + } - public void setCreatedAt(Date createdAt) { - this.createdAt = createdAt; - } + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } - public String getText() { - return text; - } + public String getText() { + return text; + } - public void setText(String text) { - this.text = text; - } + public void setText(String text) { + this.text = text; + } - public String getFromUser() { - return fromUser; - } + public String getFromUser() { + return fromUser; + } - public void setFromUser(String fromUser) { - this.fromUser = fromUser; - } + public void setFromUser(String fromUser) { + this.fromUser = fromUser; + } - public String getProfileImageUrl() { - return profileImageUrl; - } + public String getProfileImageUrl() { + return profileImageUrl; + } - public void setProfileImageUrl(String profileImageUrl) { - this.profileImageUrl = profileImageUrl; - } + public void setProfileImageUrl(String profileImageUrl) { + this.profileImageUrl = profileImageUrl; + } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((createdAt == null) ? 0 : createdAt.hashCode()); - result = prime * result - + ((fromUser == null) ? 0 : fromUser.hashCode()); - result = prime * result - + ((profileImageUrl == null) ? 0 : profileImageUrl.hashCode()); - result = prime * result + ((text == null) ? 0 : text.hashCode()); - return result; - } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((createdAt == null) ? 0 : createdAt.hashCode()); + result = prime * result + + ((fromUser == null) ? 0 : fromUser.hashCode()); + result = prime * result + + ((profileImageUrl == null) ? 0 : profileImageUrl.hashCode()); + result = prime * result + ((text == null) ? 0 : text.hashCode()); + return result; + } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - TwitterMessage other = (TwitterMessage) obj; - if (createdAt == null) { - if (other.createdAt != null) - return false; - } else if (!createdAt.equals(other.createdAt)) - return false; - if (fromUser == null) { - if (other.fromUser != null) - return false; - } else if (!fromUser.equals(other.fromUser)) - return false; - if (profileImageUrl == null) { - if (other.profileImageUrl != null) - return false; - } else if (!profileImageUrl.equals(other.profileImageUrl)) - return false; - if (text == null) { - if (other.text != null) - return false; - } else if (!text.equals(other.text)) - return false; - return true; - } + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TwitterMessage other = (TwitterMessage) obj; + if (createdAt == null) { + if (other.createdAt != null) + return false; + } else if (!createdAt.equals(other.createdAt)) + return false; + if (fromUser == null) { + if (other.fromUser != null) + return false; + } else if (!fromUser.equals(other.fromUser)) + return false; + if (profileImageUrl == null) { + if (other.profileImageUrl != null) + return false; + } else if (!profileImageUrl.equals(other.profileImageUrl)) + return false; + if (text == null) { + if (other.text != null) + return false; + } else if (!text.equals(other.text)) + return false; + return true; + } - @Override - public String toString() { - return "Tweet [createdAt=" + createdAt + ", text=" + text - + ", fromUser=" + fromUser + ", profileImageUrl=" - + profileImageUrl + "]"; - } + @Override + public String toString() { + return "Tweet [createdAt=" + createdAt + ", text=" + text + + ", fromUser=" + fromUser + ", profileImageUrl=" + + profileImageUrl + "]"; + } } diff --git a/intermediate/monitoring/src/main/java/org/springframework/integration/mvc/controller/HomeController.java b/intermediate/monitoring/src/main/java/org/springframework/integration/mvc/controller/HomeController.java index 0edf8251..1c5a11ff 100644 --- a/intermediate/monitoring/src/main/java/org/springframework/integration/mvc/controller/HomeController.java +++ b/intermediate/monitoring/src/main/java/org/springframework/integration/mvc/controller/HomeController.java @@ -1,17 +1,17 @@ /* - * Copyright 2002-2010 the original author or authors + * Copyright 2002-2012 the original author or authors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.springframework.integration.mvc.controller; @@ -33,56 +33,56 @@ import org.springframework.web.bind.annotation.RequestParam; @Controller public class HomeController { - private static final Log logger = LogFactory.getLog(HomeController.class); + private static final Log logger = LogFactory.getLog(HomeController.class); - @Autowired - private TwitterService twitterService; + @Autowired + private TwitterService twitterService; - /** - * Simply selects the home view to render by returning its name. - */ - @RequestMapping(value="/") - public String home(Model model, @RequestParam(required=false) String startTwitter, - @RequestParam(required=false) String stopTwitter, - @RequestParam(required=false) String shutdown) { + /** + * Simply selects the home view to render by returning its name. + */ + @RequestMapping(value="/") + public String home(Model model, @RequestParam(required=false) String startTwitter, + @RequestParam(required=false) String stopTwitter, + @RequestParam(required=false) String shutdown) { - if (startTwitter != null) { - twitterService.startTwitterAdapter(); - return "redirect:/"; - } + if (startTwitter != null) { + twitterService.startTwitterAdapter(); + return "redirect:/"; + } - if (stopTwitter != null) { - twitterService.stopTwitterAdapter(); - return "redirect:/"; - } + if (stopTwitter != null) { + twitterService.stopTwitterAdapter(); + return "redirect:/"; + } - if (shutdown != null) { - twitterService.shutdown(); - return "redirect:/"; - } + if (shutdown != null) { + twitterService.shutdown(); + return "redirect:/"; + } - final Collection twitterMessages = twitterService.getTwitterMessages(); + final Collection twitterMessages = twitterService.getTwitterMessages(); - logger.info("Retrieved " + twitterMessages.size() + " Twitter messages."); + logger.info("Retrieved " + twitterMessages.size() + " Twitter messages."); - model.addAttribute("twitterMessages", twitterMessages); + model.addAttribute("twitterMessages", twitterMessages); - return "home"; - } + return "home"; + } - /** - * Simply selects the home view to render by returning its name. - */ - @RequestMapping(value="/ajax") - public String ajaxCall(Model model) { + /** + * Simply selects the home view to render by returning its name. + */ + @RequestMapping(value="/ajax") + public String ajaxCall(Model model) { - final Collection twitterMessages = twitterService.getTwitterMessages(); + final Collection twitterMessages = twitterService.getTwitterMessages(); - logger.info("Retrieved " + twitterMessages.size() + " Twitter messages."); - model.addAttribute("twitterMessages", twitterMessages); + logger.info("Retrieved " + twitterMessages.size() + " Twitter messages."); + model.addAttribute("twitterMessages", twitterMessages); - return "twitterMessages"; + return "twitterMessages"; - } + } } diff --git a/intermediate/monitoring/src/main/java/org/springframework/integration/service/TwitterService.java b/intermediate/monitoring/src/main/java/org/springframework/integration/service/TwitterService.java index ac4b9d61..85cd3380 100644 --- a/intermediate/monitoring/src/main/java/org/springframework/integration/service/TwitterService.java +++ b/intermediate/monitoring/src/main/java/org/springframework/integration/service/TwitterService.java @@ -1,17 +1,17 @@ /* - * Copyright 2002-2010 the original author or authors + * Copyright 2002-2012 the original author or authors. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.springframework.integration.service; diff --git a/intermediate/monitoring/src/main/java/org/springframework/integration/service/impl/DummyTwitter.java b/intermediate/monitoring/src/main/java/org/springframework/integration/service/impl/DummyTwitter.java index 1f0b054b..0cf9f5a2 100644 --- a/intermediate/monitoring/src/main/java/org/springframework/integration/service/impl/DummyTwitter.java +++ b/intermediate/monitoring/src/main/java/org/springframework/integration/service/impl/DummyTwitter.java @@ -33,7 +33,7 @@ public class DummyTwitter { "Spring Integration is the coolest Enterprise Integration project", new Date(), "SomeUser", - null, + "http://a0.twimg.com/profile_images/1598911687/ICO_S2_Bug_normal.png", 0L, 0L, null, diff --git a/intermediate/monitoring/src/main/java/org/springintegration/NotificationListener.java b/intermediate/monitoring/src/main/java/org/springintegration/NotificationListener.java new file mode 100644 index 00000000..bcde6951 --- /dev/null +++ b/intermediate/monitoring/src/main/java/org/springintegration/NotificationListener.java @@ -0,0 +1,44 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springintegration; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * This class demonstrates the use a Spring Integration jmx adadpers to receive + * notifications, poll attributes, and invoke operations on a Remote JMX MBeanServer. + * + * @author Gary Russell + * @since 2.2 + * + */ +public class NotificationListener { + + public static void main(String[] args) throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/META-INF/spring/integration/remote-monitor-context.xml"); + Gateway gw = ctx.getBean(Gateway.class); + int cmd = 0; + while (cmd != 'q') { + cmd = System.in.read(); + gw.send((char) cmd); + } + } + + public static interface Gateway { + void send(char command); + } +} diff --git a/intermediate/monitoring/src/main/resources/META-INF/spring/integration/remote-monitor-context.xml b/intermediate/monitoring/src/main/resources/META-INF/spring/integration/remote-monitor-context.xml new file mode 100644 index 00000000..b27de3c2 --- /dev/null +++ b/intermediate/monitoring/src/main/resources/META-INF/spring/integration/remote-monitor-context.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intermediate/monitoring/src/main/resources/META-INF/spring/integration/spring-integration-context.xml b/intermediate/monitoring/src/main/resources/META-INF/spring/integration/spring-integration-context.xml index 91ab368c..65e4b1b1 100644 --- a/intermediate/monitoring/src/main/resources/META-INF/spring/integration/spring-integration-context.xml +++ b/intermediate/monitoring/src/main/resources/META-INF/spring/integration/spring-integration-context.xml @@ -49,7 +49,7 @@ - + @@ -61,19 +61,32 @@ - + - + + + + + + + diff --git a/intermediate/monitoring/src/main/resources/META-INF/spring/mvc/servlet-context.xml b/intermediate/monitoring/src/main/resources/META-INF/spring/mvc/servlet-context.xml index 0b86455d..5adae24a 100644 --- a/intermediate/monitoring/src/main/resources/META-INF/spring/mvc/servlet-context.xml +++ b/intermediate/monitoring/src/main/resources/META-INF/spring/mvc/servlet-context.xml @@ -1,32 +1,37 @@ - + - - + + - + - + - - + + - - - + + + - - - - - + + + + + diff --git a/intermediate/monitoring/src/main/resources/log4j.xml b/intermediate/monitoring/src/main/resources/log4j.xml index 7d04ecff..e5a608fe 100644 --- a/intermediate/monitoring/src/main/resources/log4j.xml +++ b/intermediate/monitoring/src/main/resources/log4j.xml @@ -6,7 +6,7 @@ - + diff --git a/intermediate/monitoring/src/test/java/org/springframework/integration/SpringIntegrationTest.java b/intermediate/monitoring/src/test/java/org/springframework/integration/SpringIntegrationTest.java index bc782e8a..9a02a5e7 100644 --- a/intermediate/monitoring/src/test/java/org/springframework/integration/SpringIntegrationTest.java +++ b/intermediate/monitoring/src/test/java/org/springframework/integration/SpringIntegrationTest.java @@ -20,15 +20,16 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Run this class to run the sample from the command line. + * * @author Gary Russell */ public class SpringIntegrationTest { - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws Exception { - new ClassPathXmlApplicationContext("/META-INF/spring/integration/spring-integration-context.xml", SpringIntegrationTest.class); - System.out.println("Hit Enter to terminate"); - System.in.read(); - } + new ClassPathXmlApplicationContext("/META-INF/spring/integration/spring-integration-context.xml", SpringIntegrationTest.class); + System.out.println("Hit Enter to terminate"); + System.in.read(); + } }