Spring Integration: how to read multiple RSS channels? - rss

I wrote my app that reads RSS feed. It works super with one channel which I have in beans.xml like this:
<feed:inbound-channel-adapter id="news"
channel="inputRssFeedChannel"
url="http://feeds.feedburner.com/Techcrunch">
<int:poller fixed-rate="5000" max-messages-per-poll="100"/>
</feed:inbound-channel-adapter>
<int:service-activator input-channel="inputRssFeedChannel"
ref="rssPrintOutService"
method="printRss"
output-channel="nullChannel"/>
Every time it just calls RssHandler which deal with SyndEntry. But what should I do if I'd like to read few rss urls (2,5,20 or etc...)?

Create your own implementation of org.springframework.integration.core.MessageSource and use it in input-channel reference like the following:
<int:inbound-channel-adapter id="newsInput" ref="newsReader">
<int:poller fixed-rate="1" time-unit="SECONDS" max-messages-per-poll="1"/>
</int:inbound-channel-adapter>
<bean id="newsReader" class="blog.NewsReader">
<property name="fetcherListener">
<bean class="blog.helper.FetcherEventListenerImpl"/>
</property>
<property name="urls">
<list>
<value>http://www.gridshore.nl/feed/</value>
<value>https://spring.io/blog.atom</value>
<value>http://feeds.foxnews.com/foxnews/video?format=xml</value>
</list>
</property>
</bean>
The class NewsReader uses list mentioned in urls propriety and retrieve the feed.
Please refer to the receive method below.
public class NewsReader implements MessageSource, InitializingBean {
private static Logger logger = LoggerFactory.getLogger(NewsReader.class);
private FeedFetcherCache feedInfoCache;
private FeedFetcher feedFetcher;
private FetcherListener fetcherListener;
private List<String> urls;
#Override
public Message receive() {
List<SyndFeed> feeds = obtainFeedItems();
return MessageBuilder.withPayload(feeds)
.setHeader("feedid", "newsfeed").build();
}
private List<SyndFeed> obtainFeedItems() {
List<SyndFeed> feed = new ArrayList<>();
try {
for (String url : urls) {
feed.add(feedFetcher.retrieveFeed(new URL(url)));
}
} catch (IOException e) {
logger.error("IO Problem while retrieving feed", e);
} catch (FeedException e) {
logger.error("Feed Problem while retrieving feed", e);
} catch (FetcherException e) {
logger.error("Fetcher Problem while retrieving feed", e);
}
return feed;
}
#Override
public void afterPropertiesSet() throws Exception {
feedInfoCache = HashMapFeedInfoCache.getInstance();
feedFetcher = new HttpURLFeedFetcher(feedInfoCache);
if (fetcherListener != null) {
feedFetcher.addFetcherEventListener(fetcherListener);
}
}
public void setFetcherListener(FetcherListener fetcherListener) {
this.fetcherListener = fetcherListener;
}
public void setUrls(List<String> urls) {
this.urls = urls;
}
In case you want to take a look of my complete code:
git clone https://github.com/BikashShaw/MultipleRSSFeedRead.git

Related

Unit test for post sling servlet aem 6.5

I have the following POST servlet that adds new node under certain resource with parameters(name and last nam) from the request:
#Component(
service = Servlet.class,
property = {
"sling.servlet.paths=/bin/createuser",
"sling.servlet.methods=" + HttpConstants.METHOD_POST
})
public class CreateNodeServlet extends SlingAllMethodsServlet {
/**
* Logger
*/
private static final Logger log = LoggerFactory.getLogger(CreateNodeServlet.class);
#Override
protected void doPost(final SlingHttpServletRequest req, final SlingHttpServletResponse resp) throws IOException {
log.info("Inside CreateNodeServlet");
ResourceResolver resourceResolver = req.getResourceResolver();
final Resource resource = resourceResolver.getResource("/content/test/us/en");
String name = req.getParameter("name");
String lastname = req.getParameter("lastname");
log.info("name :{}",name);
log.info("lastname :{}",lastname);
Node node = resource.adaptTo(Node.class);
try {
log.info("Node {}", node.getName() );
Node newNode = node.addNode(name+lastname, "nt:unstructured");
newNode.setProperty("name", name);
newNode.setProperty("lastname", lastname);
resourceResolver.commit();
} catch (RepositoryException e) {
e.printStackTrace();
} catch (PersistenceException e) {
e.printStackTrace();
}
resp.setStatus(200);
resp.getWriter().write("Simple Post Test");
}
}
I tried creating unit test for this I got this so far:
#ExtendWith(AemContextExtension.class)
class CreateNodeServletTest {
private final AemContext context = new AemContext();
private CreateNodeServlet createNodeServlet = new CreateNodeServlet();
#Test
void doPost() throws IOException, JSONException {
context.currentPage(context.pageManager().getPage("/bin/createuser"));
context.currentResource(context.resourceResolver().getResource("/bin/createuser"));
context.requestPathInfo().setResourcePath("/bin/createuser");
MockSlingHttpServletRequest request = context.request();
MockSlingHttpServletResponse response = context.response();
createNodeServlet.doPost(request, response);
JSONArray output = new JSONArray(context.response().getOutputAsString());
assertEquals("Simple Post Test", output);
}
}
however this is not working I am getting null pointer on this line
Node node = resource.adaptTo(Node.class);
can some one help what I am missing and some tips will be of great help as I am new to AEM, and there is not much resources about unit testing sling servlets ?
I think you need to register JCR_MOCK as resource resolver type
new AemContext(ResourceResolverType.JCR_MOCK);

CompanyHome reference in java API

I have a scheduler job configured and created an action class by extending org.quartz.StatefulJob
In execute method of Action Class (Shown below) , What would be the best way to get reference to CompanyHome in execute method ?
My objctive to create a file in company home directory , when the action invoke. Any suggesion ?
Have you tried using NodeLocatorService?
https://docs.alfresco.com/4.0/concepts/node-locator-available.html.
For example:
NodeRef companyHomeNodeRef = registry.getNodeLocatorService().getNode(CompanyHomeNodeLocator.NAME, null, null);
Please implement a method like this
public NodeRef getCompanyHomeNodeReference() {
NodeRef companyHomeNodeRef = null;
companyHomeNodeRef = (NodeRef)AuthenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Object>() {
public Object doWork() throws Exception {
StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore"));
ResultSet rs = serviceRegistry.getSearchService().query(storeRef, SearchService.LANGUAGE_XPATH,
"/app:company_home");
Object companyHome = null;
try {
if (rs.length() == 0) {
LOG.error("Didn't find Company Home ");
throw new AlfrescoRuntimeException("Didn't find Company Home");
}
final NodeRef companyHomeNodeRef1 = rs.getNodeRef(0);
if(companyHomeNodeRef1 == null) {
LOG.info("Didn't find Company Homes");
}else {
companyHome = companyHomeNodeRef1;
}
} finally {
rs.close();
}
return companyHome;
}
});
return companyHomeNodeRef;
}
import as below:
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.repository.StoreRef;
please see how the critical code is placed in AuthenticationUtil (this is very important).
And then use below code to create a file:
fileFolderService.create(companyNodeRef, "yourfilename", ContentModel.TYPE_CONTENT);
Add this bean in service-context.xml
<bean id="yourObj" class="MoveMonthlyDataAction">
<property name="serviceRegistry">
<ref bean="ServiceRegistry" />
</property>
</bean>
and mention in MoveMonthlyDataAction . java as below,
public class MoveMonthlyDataAction {
ServiceRegistry serviceRegistry;
public void execute(){
// your code
}
// getter and setter
}
Hope this will help.

Can I observe a LiveData object that is based on a variable query?

My code is experiencing a problem that I suspect may be self-inflicted. So I should probably answer this question first. Can I/how do I observe a LiveData object that is returned from a Dao that is based on a inner join query and a List parameter?
Unfortunately I do not yet have "10 reputation" on Stackoverflow, so apparently I cannot embed an image. But here is my ERD snapshot as it may help you see how my Entities are tying together: https://i.ibb.co/9YW0Vbx/Screenshot-at-2019-04-06-13-04-43.png
PrayerListFragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mTagViewModel = ViewModelProviders.of(this).get(TagViewModel.class);
mPrayerTagViewModel =
ViewModelProviders.of(this).get(PrayerTagViewModel.class);
...
//Update the tag list with the selected tags
mTagViewModel.getSelectedTags().observe(this, new Observer<List<Tag>>() {
#Override
public void onChanged(#Nullable List<Tag> tags) {
if(tags.size() > 0) {
mPrayerTagViewModel.setTagList(tags);
}
}
});
//Observe whatever prayers the view model has to show us
mPrayerTagViewModel.getPrayers().observe(this, new Observer<List<Prayer>>() {
#Override
public void onChanged(#Nullable List<Prayer> prayers) {
mPrayersAdapter.setPrayers(prayers);
}
});
...
}
PrayerTagViewModel
...
private List<String> mTagNames = new ArrayList<>();
...
public LiveData<List<Prayer>> getPrayers() { return getPrayersForTags(mTagNames); }
...
public void setTagList(List<Tag> tags) {
mTagNames = new ArrayList<>();
for (Tag tag: tags) {
mTagNames.add(tag.getName());
}
}
ITagDAO
This returns LiveData objects that I have no trouble observing:
#Query("SELECT * FROM tag_table ORDER BY name")
LiveData<List<Tag>> getAll();
#Query("SELECT * FROM tag_table WHERE selected ORDER BY name")
LiveData<List<Tag>> getSelected();
IPrayerTagDAO
But I am running into issues observing this, so I want to first make sure it is valid syntax:
#Query("SELECT * FROM prayer_table " +
"INNER JOIN prayertag_table " +
"ON summary=fk_summary " +
"WHERE fk_name IN (:names)")
LiveData<List<Prayer>> getPrayersForTags(final List<String> names);
If it is valid syntax, am I possibly losing my observable in my fragment because the call to getPrayers() in PrayerTagViewModel returns a new ViewModel, i.e. a different ViewModel than the one I have started observing in the fragment??
Persistence paid off! I had a sneaky suspicion the mysterious Transformations.switchMap could resolve my issue, but only after a lot more reading did I realize how.
PrayerTagViewModel (modified)
...
private PrayerTagRepository mPrayerTagRepository;
private MutableLiveData<List<String>> mTags = new MutableLiveData<>();
private LiveData<List<Prayer>> mPrayers =
Transformations.switchMap(mTags, mTags -> getPrayersForTags(mTags));
public PrayerTagViewModel(#NonNull Application application) {
super(application);
mPrayerTagRepository = PrayerTagRepository.getRepository(application);
}
...
public LiveData<List<Prayer>> getPrayersForTags(final List<String> names) {
return mPrayerTagRepository.getPrayersForTags(names);
}
public LiveData<List<Prayer>> getPrayers() { return mPrayers; }
...
public void setTagList(List<Tag> tags) {
List<String> tagNames = new ArrayList<>();
for (Tag tag: tags)
tagNames.add(tag.getName());
mTags.setValue(tagNames);
}
PrayersListFragment (modified)
...
//Update the tag list with the selected tags
mTagViewModel.getSelectedTags().observe(this, new Observer<List<Tag>>() {
#Override
public void onChanged(#Nullable List<Tag> tags) {
Log.i(this.getClass().getName(),"onChanged :: Tag size = " + tags.size());
if(tags.size() > 0)
mPrayerTagViewModel.setTagList(tags);
}
});
//Observe whatever prayers the view model has to show us
mPrayerTagViewModel.getPrayers().observe(this,
prayers -> mPrayersAdapter.setPrayers(prayers));
Solution: The switchMap lets my Fragment observe a dynamically changing LiveData (actually a MutableLiveData) from my ViewModel.

Associate async task's completion/progress monitor with session

I want to be able to perform an asynchronous task in java and be able to keep a completion (and if possible progress) monitor associated to the user's session. Is this possible, and if yes what is the way to do it?
Currently the task is implemented synchronously as a stateless session bean method, which is called from a jax-rs endpoint.
I looked at https://docs.oracle.com/javaee/7/tutorial/ejb-async001.htm but AsyncResult is not serializable so I guess I cannot add it to session.
Using the Spring annotation #Async, you can make any bean/method asynchronous.
The container will create a new thread and method will be executed asynchronously. You can as well pass a session object into this method and upon completion, you can mark an attribute in the session object.
Example:- https://spring.io/guides/gs/async-method/
JSF example, works in Wildfly:
1 inside in view (xhtml) we have an upload form and progress meter
<h:form>
<div align="justify">
<p:fileUpload style="width: auto" fileUploadListener="#{fileUploadCtrl.handleFileUpload}" mode="advanced" label="Please pick XLS file" update="messages" auto="true" sizeLimit="1000000" allowTypes="/(\.|\/)(xls|xlsx)$/" />
<p:growl id="messages" showDetail="false" life="4000"/>
</div>
</h:form>
<h:form id="wholeform">
<h:outputText id="statusot" value="#{fileUploadCtrl.message}" />
<p:spacer width="10" height="10"/>
<p:poll interval="1" listener="#{fileUploadCtrl.updateStatus}" update="wholeform" />
</h:form>
2 in controller, which is a managed bean, we process file and once a second update status
#ManagedBean
#ViewScoped
public class FileUploadCtrl {
#EJB
private SomeBusinessLogicClass model;
#EJB
private ProgressTracker progress;
private Future<List<String>> asyncResult;
private int progressId = 0;
private String message;
private boolean busy = false;
public void handleFileUpload(FileUploadEvent event) {
Set<String> ids = model.populate(event.getFile().getContents());
progressId = progress.newIndex();
asyncResult = model.process(ids);
busy = true;
FacesMessage message = new FacesMessage("Loaded " + ids.size() + " objects", "");
FacesContext.getCurrentInstance().addMessage(null, message);
}
public void updateStatus() {
if (!busy)
return;
try {
if (asyncResult.isDone()) {
List<String> r = asyncResult.get();
message = "Job done";
busy = false;
progress.delIndex(progressId);
} else {
message = progress.getIndex(progressId)+"-th element in work";
}
} catch (Exception e) {
System.out.println("updateStatus " + e.toString());
}
}
3 All business logic is in EJBs like SomeBusinessLogicClass or many others. Also we need a simple progress-manager EJB, I post it completely
#Singleton
public class ProgressTracker {
private Map<Integer,Integer> indexes = new HashMap<>();
public Map<Integer, Integer> getIndexes() {
return indexes;
}
public void setIndexes(Map<Integer, Integer> indexes) {
this.indexes = indexes;
}
public Integer newIndex() {
Integer size = indexes.size();
indexes.put(size,0);
return size;
}
public void incIndex(final Integer index) {
int old = indexes.get(index);
old++;
indexes.put(index,old);
}
public Integer getIndex(final Integer index) {
return indexes.get(index);
}
public void delIndex(Integer index) {
indexes.remove(index);
}
}
Maybe this example is not elegant, I'm almost newbie with frontends, but it is working and better, than nothing.

Issue with retrieveing the Manager of a System User in a Custom workflow - CRM 2013

Issues with custom workflow activity in CRM 2013 On-prem
I'm trying to pass the Manager of the System
here is the code that I'm running, it gets to setting the MANAGER and stops
I put the ran the FetchXML seperatly and it does return a value so I know what bit works
public class CaseAccountManagerManagersLookup : CodeActivity
{
// Inputs
[Input("Enter Case")]
[ReferenceTarget("incident")]
public InArgument<EntityReference> CA { get; set; }
// Outputs
[Output("Manager Output")]
[ReferenceTarget("systemuser")]
public OutArgument<EntityReference> AMOUT { get; set; }
protected override void Execute(CodeActivityContext executionContext)
{
// Context
IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
//Create the tracing service
ITracingService tracingService = executionContext.GetExtension<ITracingService>();
// get the account and renewals manager ID's
var CASE = CA.Get<EntityReference>(executionContext);
tracingService.Trace("Case ID = " + CASE.Id);
try
{
// FETCH
string fetchXml = string.Format(#"
<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='incident'>
<attribute name='title' />
<attribute name='incidentid' />
<order attribute='title' descending='false' />
<filter type='and'>
<condition attribute='incidentid' operator='eq' value='{0}' />
</filter>
<link-entity name='contact' from='contactid' to='customerid' alias='ak'>
<link-entity name='account' from='accountid' to='parentcustomerid' alias='al'>
<link-entity name='systemuser' from='systemuserid' to='bc_dssalesperson' alias='am'>
<attribute name='parentsystemuserid' />
</link-entity>
</link-entity>
</link-entity>
</entity>
</fetch>", CASE.Id);
EntityCollection case_results = service.RetrieveMultiple(new FetchExpression(fetchXml));
//tracingService.Trace("fetch has run");
if (case_results.Entities.Count != 0)
{
foreach (var a in case_results.Entities)
{
//if (a.Attributes.Contains("ai_parentsystemuserid"))
//{
tracingService.Trace("set manager id next");
var MANAGERID = (EntityReference)a.Attributes["parentsystemuserid"];
tracingService.Trace("manager id set");
AMOUT.Set(executionContext, MANAGERID);
throw new InvalidOperationException("Want to see trace");
//}
}
}
tracingService.Trace("end ");
}
catch (Exception e)
{
throw new InvalidPluginExecutionException("Plugin - CaseAccountManagerManagerLookup - " + e.Message);
}
finally
{
throw new InvalidOperationException("Want to see trace");
}
}
}
Try to use am.parentsystemuserid instead of just parentsystemuserid.
Are you sure that the guid that you are passing is in the correct form?
{8B8099A6-8B89-E411-883D-D89D676552A0}
this is what i get from the export but you are writing
8B8099A6-8B89-E411-883D-D89D676552A0
Also are you sure about the record that you are trying to retrieve? Is the chain complete with data?
case-> contact -> account -> parent user -> parent user ?

Resources