Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 94 Current »

[11:14:14 CDT(-0500)] <EricDalquist> athena: looks like you're handling pull 44?

[11:15:21 CDT(-0500)] <athena> hey eric

[11:15:22 CDT(-0500)] <athena> yes

[11:15:29 CDT(-0500)] <athena> think they're going to refactor that using the existing library

[11:15:42 CDT(-0500)] <athena> i've also written a factory for those jaxb elements

[11:15:48 CDT(-0500)] <athena> so they're less painful and verbose to create in xml

[11:15:56 CDT(-0500)] <EricDalquist> cool

[11:16:50 CDT(-0500)] <athena> by the way, did you ever experiment with ways to call a portal REST service from a portlet?

[11:16:59 CDT(-0500)] <EricDalquist> yes

[11:17:01 CDT(-0500)] <EricDalquist> it is possible

[11:17:03 CDT(-0500)] <EricDalquist> but gross (tongue)

[11:17:14 CDT(-0500)] <athena> i seem to remember you writing a portlet that called the portal's portlet list service

[11:17:15 CDT(-0500)] <athena> gotcha (smile)

[11:17:19 CDT(-0500)] <EricDalquist> yeah

[11:17:29 CDT(-0500)] <athena> did your portlet re-use the portal session?

[11:17:34 CDT(-0500)] <EricDalquist> yes

[11:17:37 CDT(-0500)] <EricDalquist> so here is the concept"

[11:18:35 CDT(-0500)] <EricDalquist> you create a servlet (spring spring servlet controller). This servlet does a cross-context lookup for the portal context then creates a request dispatcher for that context with the rest API uri

[11:19:36 CDT(-0500)] <EricDalquist> the servlet uses a response wrapper to capture ALL of the output (to prevent mucking with the portlet's response)

[11:20:00 CDT(-0500)] <EricDalquist> the servlet then sets the response data in some sort of request attribute data structure

[11:20:17 CDT(-0500)] <EricDalquist> your portlet code can create a request dispatcher to talk to that custom servlet

[11:20:23 CDT(-0500)] <EricDalquist> so ...

[11:20:26 CDT(-0500)] <athena> that makes sense

[11:20:49 CDT(-0500)] <athena> would it make sense for us to have a reusable library for that logic?

[11:21:11 CDT(-0500)] <EricDalquist> PortletController -> PortletRequestDispatcher.include -> PortalProxyingServlet -> PortalContextLookup -> RequestDisptacher.include ->

[11:21:20 CDT(-0500)] <EricDalquist> if we want to encourage this

[11:21:21 CDT(-0500)] <EricDalquist> yes

[11:21:25 CDT(-0500)] <athena> well

[11:21:26 CDT(-0500)] <EricDalquist> we would have to do a resuable lib

[11:21:30 CDT(-0500)] <EricDalquist> it would be insane otherwise

[11:21:33 CDT(-0500)] <athena> yeah.

[11:21:39 CDT(-0500)] <athena> i guess the question is whether we want to encourage it

[11:21:42 CDT(-0500)] <EricDalquist> we would also need to standardize on the data returned

[11:21:45 CDT(-0500)] <EricDalquist> yeah

[11:21:52 CDT(-0500)] <EricDalquist> I'm not sure what our alternatives are :/

[11:22:00 CDT(-0500)] <EricDalquist> this is good because it never leaves tomcat

[11:22:03 CDT(-0500)] <athena> but it seems like there's a legitimate use case for wanting to query the portal's person directory, permission store, etc.

[11:22:11 CDT(-0500)] <EricDalquist> so you avoid self-call issues

[11:22:19 CDT(-0500)] <athena> and seems like REST services are a reasonable way to do it

[11:22:19 CDT(-0500)] <EricDalquist> the other option

[11:22:24 CDT(-0500)] <EricDalquist> is we create a resuable library

[11:22:28 CDT(-0500)] <EricDalquist> that just does direct API calls

[11:22:43 CDT(-0500)] <EricDalquist> just a sec ...

[11:23:09 CDT(-0500)] <athena> would a library that does direct API calls really work? wouldn't we need to recreate all the XML config?

[11:23:37 CDT(-0500)] <EricDalquist> no

[11:23:50 CDT(-0500)] <EricDalquist> so what we would do is define truly public APIs

[11:24:05 CDT(-0500)] <EricDalquist> this API jar would live in tomcat/shared/lib

[11:24:19 CDT(-0500)] <EricDalquist> when uPortal starts up it would bootstrap this API jar by injecting an implementation

[11:24:32 CDT(-0500)] <EricDalquist> wait

[11:24:36 CDT(-0500)] <EricDalquist> ignore that 2nd line

[11:24:46 CDT(-0500)] <EricDalquist> so we would create an API jar and it would live in shared/lib

[11:25:04 CDT(-0500)] <athena> gotcha

[11:25:09 CDT(-0500)] <athena> yeah, that makes sense

[11:25:11 CDT(-0500)] <EricDalquist> then the portal would provide impls of this API as PortalContext attributes

[11:25:18 CDT(-0500)] <athena> of course, that requires a bunch of planning and design effort

[11:25:27 CDT(-0500)] <athena> that i bet we don't actually have the resources to do right now (smile)

[11:25:42 CDT(-0500)] <EricDalquist> so you could do:

[11:25:43 CDT(-0500)] <EricDalquist> PersonDir pd = (PersonDir)portalContext.getAttribute("org.jasig.portal.personDirectory");

[11:25:46 CDT(-0500)] <EricDalquist> right

[11:25:52 CDT(-0500)] <athena> though that does sound like a nice architectural plan

[11:25:53 CDT(-0500)] <EricDalquist> but it would provide isolation from portlets

[11:25:58 CDT(-0500)] <EricDalquist> and be sane to support

[11:25:59 CDT(-0500)] <athena> yeah

[11:26:09 CDT(-0500)] <EricDalquist> the danger with all of this is if we don't commit to doing that work

[11:26:14 CDT(-0500)] <EricDalquist> we WILL hate ourselves in 2 years

[11:26:19 CDT(-0500)] <EricDalquist> and it will be painful

[11:26:53 CDT(-0500)] <athena> yeah

[11:27:02 CDT(-0500)] <athena> and it would be really nice to have person directory and group support for our portlets

[11:27:45 CDT(-0500)] <EricDalquist> so you mean getting attributes for users other than the curent user

[11:27:50 CDT(-0500)] <EricDalquist> and doing more than role checking?

[11:27:56 CDT(-0500)] <EricDalquist> because if we expose that

[11:28:03 CDT(-0500)] <EricDalquist> we really need to get permissioning in place as well

[11:28:11 CDT(-0500)] <EricDalquist> or we're going to have security problems

[11:29:04 CDT(-0500)] <athena> well, we already have a REST feed that does that

[11:29:07 CDT(-0500)] <athena> and it does check user permissions

[11:29:18 CDT(-0500)] <athena> that's how the uMobile native app's directory works

[11:29:19 CDT(-0500)] <EricDalquist> yup

[11:29:31 CDT(-0500)] <athena> it contacts the /people.json service using it's existing portal session

[11:29:53 CDT(-0500)] <athena> and that filters results by VIEW_USER and VIEW_USER_ATTRIBUTE

[11:30:08 CDT(-0500)] <athena> so drew's use case is to do something similar, but from a portlet

[11:30:29 CDT(-0500)] <athena> seems like a reasonable use case for messaging portlets, etc. as well

[11:30:36 CDT(-0500)] <EricDalquist> yup

[11:31:03 CDT(-0500)] <EricDalquist> so our API via request attribute approach could still call the controllers

[11:31:14 CDT(-0500)] <athena> yeah - it sounds like that would work today

[11:31:16 CDT(-0500)] <EricDalquist> especially if the controller doesn't actually need the req/req

[11:31:18 CDT(-0500)] <EricDalquist> req/res

[11:31:35 CDT(-0500)] <athena> i think it does, so that it can check the session?

[11:32:52 CDT(-0500)] <EricDalquist> hrm

[11:33:04 CDT(-0500)] <EricDalquist> what is the controller for that rest feed?

[11:35:17 CDT(-0500)] <athena> PeopleRESTController.java

[11:35:59 CDT(-0500)] <EricDalquist> hrm

[11:36:04 CDT(-0500)] <EricDalquist> yeah that needs req and res

[11:39:52 CDT(-0500)] <athena> yeah - i think most of our services would

[11:40:10 CDT(-0500)] <athena> if they didn't need a session we could just make a normal call and skip all the session handling stuff

[11:44:27 CDT(-0500)] <drewwills> hey folks – sorry, was in a mtg

[11:50:17 CDT(-0500)] <drewwills> I can enhance the rest controllers to optionally permit localhost traffic

[11:50:25 CDT(-0500)] <drewwills> w/o a session

[11:50:37 CDT(-0500)] <EricDalquist> that won't work

[11:50:40 CDT(-0500)] <EricDalquist> at least not portably

[11:50:57 CDT(-0500)] <EricDalquist> for example our portal isntances can't talk to themselves on localhost

[11:50:57 CDT(-0500)] <EricDalquist> or on the portal's host name

[11:51:09 CDT(-0500)] <drewwills> and btw I really like the path of leveraging the REST apis b/c we're already putting so much good investment there

[11:51:10 CDT(-0500)] <EricDalquist> as an artifact of how our hardware load balancer networking gear works

[11:51:29 CDT(-0500)] <EricDalquist> did you read the logs of our chat drewwills?

[11:51:35 CDT(-0500)] <drewwills> i did

[11:52:14 CDT(-0500)] <drewwills> i aslo like the requestDispatcher – as opposed to httpClient – method

[11:52:48 CDT(-0500)] <drewwills> and fwiw our immediate use cases are slightly less ugly b/c I'll be making these calls from spring WEB wvc

[11:53:32 CDT(-0500)] <drewwills> i think... catching up w/ myself here... thinking and typing at the same time (tongue)

[11:54:20 CDT(-0500)] <drewwills> can't a portllet get a cross-context requestDispatcher anyway?

[11:55:02 CDT(-0500)] <EricDalquist> well remember the httpclient method is NOT portable

[11:55:02 CDT(-0500)] <EricDalquist> and not something we can include/distribute due to that

[11:55:14 CDT(-0500)] <EricDalquist> ok

[11:55:36 CDT(-0500)] <EricDalquist> so a portlet can't directly do cross-context

[11:55:41 CDT(-0500)] <EricDalquist> but it can via a servlet in the same webapp

[11:56:01 CDT(-0500)] <EricDalquist> PortletController -> PortletRequestDispatcher.include -> PortalProxyingServlet -> PortalContextLookup -> RequestDisptacher.include -> RestController

[11:56:21 CDT(-0500)] <drewwills> roger

[11:56:26 CDT(-0500)] <EricDalquist> we could encapsulate "-> PortletRequestDispatcher.include -> PortalProxyingServlet -> PortalContextLookup -> RequestDisptacher.include -> RestController" in a stand alone library

[11:57:17 CDT(-0500)] <EricDalquist> we would also need to figure out what data type would be returned

[11:57:27 CDT(-0500)] <drewwills> so when that request comes in, what does the session look like from the persspective of the rest controller portal-side?

[11:57:37 CDT(-0500)] <drewwills> is it the user's actual httpsession?

[11:57:38 CDT(-0500)] <EricDalquist> it is the user's portal session

[11:57:45 CDT(-0500)] <drewwills> rock & roll

[11:57:52 CDT(-0500)] <EricDalquist> I think we could encapsulate this enough to have it be a plain old API

[11:58:03 CDT(-0500)] <EricDalquist> give me 10 minutes to chat with JimH here in my office

[11:58:03 CDT(-0500)] <drewwills> that would automatically filter appropriately, correct?

[11:58:05 CDT(-0500)] <EricDalquist> and we can talk more about it

[11:58:16 CDT(-0500)] <drewwills> i need to hit a mtg too

[11:58:20 CDT(-0500)] <drewwills> bb in 1 hr or less

[13:07:58 CDT(-0500)] <drewwills> back from my mtg, if there's more ground to cover

[13:08:16 CDT(-0500)] <EricDalquist1> yes

[13:08:20 CDT(-0500)] <EricDalquist1> but I just sat down to eat

[13:08:25 CDT(-0500)] <EricDalquist1> give me 15 minutes or so

[13:08:27 CDT(-0500)] <EricDalquist1> and we cn chat a bit more

[13:08:40 CDT(-0500)] <drewwills> lol, i'd like to give you more than 15 min to eat

[13:08:54 CDT(-0500)] <drewwills> i know i'm demending, but I do have standards (wink)

[13:10:43 CDT(-0500)] <EricDalquist1> (smile)

[13:26:04 CDT(-0500)] <EricDalquist> ok drewwills

[13:26:16 CDT(-0500)] <EricDalquist> as long as our firewall doesn't decide to block everything again

[13:26:19 CDT(-0500)] <EricDalquist> I should be all set

[13:30:21 CDT(-0500)] <drewwills> great

[13:31:32 CDT(-0500)] <EricDalquist> so a few things that need to get figured out:

[13:31:32 CDT(-0500)] <EricDalquist> what is the result data format

[13:31:32 CDT(-0500)] <EricDalquist> how much API do we encode in the utility library

[13:32:20 CDT(-0500)] <EricDalquist> a very simple util library could look like:

[13:32:20 CDT(-0500)] <EricDalquist> Object callPortalApi(PortletRequest, PortletResponse, String uri, Map<String, String[]> parameters)

[13:32:31 CDT(-0500)] <EricDalquist> and just hide all of the gross stuff

[13:32:32 CDT(-0500)] <drewwills> yep

[13:32:49 CDT(-0500)] <EricDalquist> the portlet would then just have to configure the generic "portal call proxy servlet" in web.xml

[13:32:55 CDT(-0500)] <EricDalquist> and configure the portal's webappname

[13:33:02 CDT(-0500)] <drewwills> could even be "public JsonNode"

[13:33:02 CDT(-0500)] <EricDalquist> though we could add that as a request property

[13:33:10 CDT(-0500)] <EricDalquist> which I would vote for

[13:33:19 CDT(-0500)] <EricDalquist> publicJsonNode?

[13:33:44 CDT(-0500)] <drewwills> instead of Object, we could have a more specific return type... which could be JsonNode

[13:33:51 CDT(-0500)] <EricDalquist> right

[13:33:58 CDT(-0500)] <EricDalquist> though that then forces the choice of JSON library on the portlet

[13:34:08 CDT(-0500)] <EricDalquist> so if we do that we say pick Jackson

[13:34:15 CDT(-0500)] <EricDalquist> then they are forced to use Jackson

[13:34:22 CDT(-0500)] <EricDalquist> not sure if that is an issue or not

[13:34:33 CDT(-0500)] <EricDalquist> maybe reasonable since jackson is what Spring3 uses for all its json stuff

[13:34:43 CDT(-0500)] <EricDalquist> and that is what most of our portlets use or will use for a framework

[13:35:08 CDT(-0500)] <drewwills> or we could add a Class parameter to the method and expose the features of the RestTemplate.getForObject or whatever

[13:43:23 CDT(-0500)] <EricDalquist> sorry .. lost network again

[13:43:25 CDT(-0500)] <EricDalquist> just a minute

[13:43:48 CDT(-0500)] <drewwills> sure

[13:45:27 CDT(-0500)] <drewwills> and maybe i'm missing something... how do we hit a uri through a RequestDispatcher while using a RestTemplate anyway? I don't think I have that peice of the puzzle in my head atm

[13:46:16 CDT(-0500)] <EricDalquist> you can't

[13:46:21 CDT(-0500)] <EricDalquist> we have to write all that handling logic

[13:46:32 CDT(-0500)] <EricDalquist> so the way this works is:

[13:47:03 CDT(-0500)] <drewwills> oh noes

[13:47:20 CDT(-0500)] <drewwills> i was getting quite fond of that RestTemplate interface

[13:47:20 CDT(-0500)] <EricDalquist> 1. PortletController creates a PortletRequestDispatcher to ServletController

[13:47:44 CDT(-0500)] <EricDalquist> 2. PortletController calls prd.include(PortletRequest, PortletResponse)

[13:48:16 CDT(-0500)] <EricDalquist> 3. ServletController uses ServletContext.getContext("/uPortal") to get uPortal's ServletContext object

[13:48:51 CDT(-0500)] <EricDalquist> 4. ServletController creates a RequestDispatcher using uportalsServletContext.createRequestDispatcher("/rest/uri");

[13:49:43 CDT(-0500)] <EricDalquist> 5. ServletController calls rd.include(request, responseWrapper) //That is a HttpServletResponseWrapper that captures EVERYTHING so the response data written doesn't break the portlet's response

[13:50:21 CDT(-0500)] <EricDalquist> 6. ServletController grabs the String or byte[]+encoding data written out by the portal's rest UI

[13:50:51 CDT(-0500)] <EricDalquist> 6. ServletController converts this to some pre-defined data structure (JsonNode?) and stores it in a well named request attribute

[13:51:06 CDT(-0500)] <EricDalquist> 7. PortletController pulls the data out of the well named request attribute

[13:51:07 CDT(-0500)] <EricDalquist> tada

[13:51:13 CDT(-0500)] <drewwills> oh jeez

[13:51:14 CDT(-0500)] <EricDalquist> wonderfully gross

[13:51:46 CDT(-0500)]

<drewwills> this is much easier to follow and implement: JsonNode json = restTemplate.getForObject("http://localhost:8080/ssp-platform/api/people.json?searchTerms\[\]=

Unknown macro: {searchTerms}

&username=

Unknown macro: {username}

", JsonNode.class, params);

[13:51:46 CDT(-0500)] <EricDalquist> and remember the portlet is already one request dispatcher deep (that is how uportal/pluto renders portlets, via a cross context request dispatcher)

[13:51:51 CDT(-0500)] <EricDalquist> yes

[13:51:54 CDT(-0500)] <EricDalquist> but that will break

[13:51:59 CDT(-0500)] <drewwills> yeah i remeber localhost

[13:52:05 CDT(-0500)] <EricDalquist> if you try that on our servers they drop off the network

[13:52:32 CDT(-0500)] <EricDalquist> as an artifact of the networking magic that goes on with hardware load balancers

[13:52:54 CDT(-0500)] <EricDalquist> so an alternative is to put work into defining a uPortal specifc API

[13:53:00 CDT(-0500)] <EricDalquist> we create a -api JAR

[13:53:06 CDT(-0500)] <EricDalquist> that gets deployed to shared/lib

[13:53:23 CDT(-0500)] <EricDalquist> then provide impls of those APIs as PortalContext attributes

[13:53:30 CDT(-0500)] <EricDalquist> so you'd do something like:

[13:53:34 CDT(-0500)] <drewwills> yes actually this was the Academus approach

[13:54:02 CDT(-0500)] <EricDalquist> PersonLookupService please = (PersonLookupService)portalContext.getAttribute("org.jasig.portal.api.personLookup")

[13:54:17 CDT(-0500)] <EricDalquist> which isn't unreasonable

[13:54:21 CDT(-0500)] <drewwills> public static void setInternalApiMajic(); // called from portal

[13:54:25 CDT(-0500)] <EricDalquist> no

[13:54:35 CDT(-0500)] <EricDalquist> not the shared/injected static API approach

[13:54:47 CDT(-0500)] <EricDalquist> the portlets get the API reference from the PortalContext interface which is part of the portlet spec

[13:55:01 CDT(-0500)] <EricDalquist> and only hold it for the duration of the portlet's lifecycle

[13:55:12 CDT(-0500)] <EricDalquist> it at least prevents classloader leakage

[13:55:38 CDT(-0500)] <EricDalquist> the shared API may actually be more maintainable

[13:55:46 CDT(-0500)] <EricDalquist> since then we have a concrete class structure

[13:55:54 CDT(-0500)] <drewwills> how much would you have to put in the shared classloader? just the interface(s)?

[13:56:00 CDT(-0500)] <EricDalquist> just the interfaces

[13:56:17 CDT(-0500)] <EricDalquist> the rest api approach could be bad unless we add unit tests for every rest API that asserts the output data format

[13:56:21 CDT(-0500)] <EricDalquist> and commit to never changing it

[13:56:38 CDT(-0500)] <EricDalquist> the shared API approach makes that requirement more apparent

[13:56:46 CDT(-0500)] <EricDalquist> as we would have a specifically defined public APUI

[13:59:00 CDT(-0500)] <drewwills> i suppose under-the-hood we could have the same code do the heavy lifting for both the REST & Java APIs, e.g. PersonLookupHelperImpl

[13:59:05 CDT(-0500)] <EricDalquist> yup

[13:59:10 CDT(-0500)] <EricDalquist> so we get the API impl

[13:59:27 CDT(-0500)] <EricDalquist> then refactor the rest api to use the same service

[14:00:19 CDT(-0500)] <drewwills> i haven't looked, but i bet you will find the REST api already closer to that atm than you would have, say, 2005

[14:00:43 CDT(-0500)] <EricDalquist> oh I'm sure

[14:00:46 CDT(-0500)] <drewwills> i'm looking at PeopleRESTController

[14:00:58 CDT(-0500)] <EricDalquist> this will all also get easier once we get moved completely to spring-security

[14:01:01 CDT(-0500)] <EricDalquist> for authn and authz

[14:01:02 CDT(-0500)] <drewwills> and it seems to hold tolerably to the One Responsibility Rule

[14:01:10 CDT(-0500)] <EricDalquist> then we have less concern over req/res access

[14:01:23 CDT(-0500)] <EricDalquist> as access state will be managed in a ThreadLocal by spring-security

[14:01:28 CDT(-0500)] <drewwills> doing controller-y things, and delegating the deeper things to other classes

[14:01:57 CDT(-0500)] <drewwills> athena?

[14:02:10 CDT(-0500)] <drewwills> anyone else want to comment on direction?

[14:03:03 CDT(-0500)] <peterjhart> no

[14:03:10 CDT(-0500)] <drewwills> i need to head to lunch... bb in a bit

[14:03:14 CDT(-0500)] <EricDalquist> k

[14:03:20 CDT(-0500)] <EricDalquist> I'll be here for ~3 more hours

[14:47:16 CDT(-0500)] <athena> back - was at lunch

[14:52:33 CDT(-0500)] <athena> ok

[14:52:37 CDT(-0500)] <athena> read over the above

[14:52:45 CDT(-0500)] <athena> so first of all, we actually do need the REST services for other things

[14:52:48 CDT(-0500)] <athena> specifically umobile

[14:52:54 CDT(-0500)] <athena> but potentially also useful for other applications

[14:53:09 CDT(-0500)] <athena> so i think regardless of whether we create another API or not we still need to standardize those REST services

[14:53:17 CDT(-0500)] <athena> also, i'd recommend that we don't cast to JsonNode3

[14:53:29 CDT(-0500)] <athena> that takes some freedom away from the client projects

[14:53:35 CDT(-0500)] <athena> since i might want the results back as a map

[14:53:47 CDT(-0500)] <athena> or i might want to create a lightweight java pojo to bind to

[14:54:09 CDT(-0500)] <athena> we should support those kind of choices from the client

[14:54:20 CDT(-0500)] <athena> maybe the solution would be to have the expected type as a parameter

[14:54:29 CDT(-0500)] <athena> and then we can use then when calling objectMapper.readValue

[14:54:39 CDT(-0500)] <athena> makes the API friendlier but doesn't take that flexibility away from the client

[14:58:01 CDT(-0500)] <EricDalquist> athena: so you're saying that no matter what we need to standardize our REST APIs

[14:58:27 CDT(-0500)] <EricDalquist> and because of that we might as well do the dispatcher chaining trick to just use those

[14:59:16 CDT(-0500)] <athena> yes

[14:59:20 CDT(-0500)] <EricDalquist> ok

[14:59:22 CDT(-0500)] <EricDalquist> I'm fine with that

[14:59:26 CDT(-0500)] <athena> unless someone really has time to create those new standalone APIs

[14:59:31 CDT(-0500)] <athena> i mean i think that would be a terrific move

[14:59:37 CDT(-0500)] <EricDalquist> but I think we need to add more tests that assert the output format

[14:59:43 CDT(-0500)] <athena> but from talking to drew, it doesn't sound to me like he has time to do that as part of his project

[14:59:46 CDT(-0500)] <EricDalquist> so that refactoring doesn't break integrations

[14:59:50 CDT(-0500)] <athena> yes, that sounds like a great idea

[15:00:00 CDT(-0500)] <athena> and i think we probably already need to start doing that anyway

[15:00:06 CDT(-0500)] <athena> so that sounds like a great idea to me

[15:00:26 CDT(-0500)] <athena> and since umobile uses these services, i can probably help out

[15:02:28 CDT(-0500)] <athena> so how much of this can we abstract away from the portlet's implementation?

[15:02:45 CDT(-0500)] <EricDalquist> quite a bit

[15:02:46 CDT(-0500)] <athena> can it just be a target url, some parameters, and an expected return type?

[15:03:05 CDT(-0500)] <EricDalquist> so one thing I think we need to do is add a portlet request property that tells the portlet the portal's context path

[15:03:08 CDT(-0500)] <EricDalquist> which would be easy enough to do

[15:03:19 CDT(-0500)] <athena> oh that's be pretty cool

[15:03:26 CDT(-0500)] <EricDalquist> we have to have that really

[15:03:29 CDT(-0500)] <EricDalquist> or people will go nuts

[15:03:33 CDT(-0500)] <EricDalquist> and it is easy to add

[15:03:35 CDT(-0500)] <athena> some of the portlet's already have a config string in them

[15:03:43 CDT(-0500)] <athena> that in umobile gets copied from the filter file

[15:04:02 CDT(-0500)] <athena> so we could go that approach, but using something more automagic would be even better

[15:04:09 CDT(-0500)] <EricDalquist> then we create an API that looks like "public Object callPortalRestApi(PortletRequest, PortletResponse, String uri, Map<String, String[]> params)

[15:04:28 CDT(-0500)] <EricDalquist> not sure what we do for return type stil

[15:04:38 CDT(-0500)] <EricDalquist> that depends on how many external libs we depend on in this utility library

[15:04:52 CDT(-0500)] <athena> ah, good point

[15:05:00 CDT(-0500)] <athena> maybe we could have two methods?

[15:05:10 CDT(-0500)] <athena> one that just returns whatever the raw thing is and lets the portlet handle it itself

[15:05:25 CDT(-0500)] <athena> and one that uses jackson and takes a class as a parameter?

[15:06:01 CDT(-0500)] <EricDalquist> but what is the raw thing?

[15:06:02 CDT(-0500)] <athena> that probably covers the expected use and only pulls in one lib, but lets the portlet have flexibility if it needs it

[15:06:11 CDT(-0500)] <EricDalquist> this approach will have one of two things

[15:06:13 CDT(-0500)] <EricDalquist> a String

[15:06:19 CDT(-0500)] <EricDalquist> or a byte[] and encoding

[15:06:36 CDT(-0500)] <EricDalquist> since we're literally capturing the rest api response data

[15:07:53 CDT(-0500)] <athena> so is the concern that we're not sure which of those to send back?

[15:08:09 CDT(-0500)] <EricDalquist> so we have two options

[15:08:13 CDT(-0500)] <EricDalquist> one is we always return a String

[15:08:37 CDT(-0500)] <EricDalquist> and just do new String(byte[], encoding) if the rest API wrote to the output stream instead of the writer

[15:09:12 CDT(-0500)] <athena> do we have expected use cases where something other than a string would be returned?

[15:09:19 CDT(-0500)] <EricDalquist> I don't know (smile)

[15:09:31 CDT(-0500)] <EricDalquist> if you wanted to use the import/export rest APIs then yes

[15:09:38 CDT(-0500)] <EricDalquist> oh

[15:09:39 CDT(-0500)] <athena> ok, that's fair enough

[15:09:46 CDT(-0500)] <EricDalquist> well this is limited in a way to

[15:09:52 CDT(-0500)] <EricDalquist> well no

[15:09:55 CDT(-0500)] <EricDalquist> never mind that last line

[15:09:58 CDT(-0500)] <athena> so could we have two versions?

[15:10:10 CDT(-0500)] <athena> 1. sends back a byte[] and encoding

[15:10:25 CDT(-0500)] <athena> and 2. uses Jackson to parse the response and cast it to the provided type

[15:10:43 CDT(-0500)] <athena> it seems like that'd make the API friendly but still let you connect to something more low-level if you needed to?

[15:11:37 CDT(-0500)] <EricDalquist> well 1 would need to return something like:

[15:11:37 CDT(-0500)] <EricDalquist> RestResponse {

[15:11:37 CDT(-0500)] <EricDalquist> String writerOutput;

[15:11:37 CDT(-0500)] <EricDalquist> byte[] streamOutput;

[15:11:37 CDT(-0500)] <EricDalquist> String streamEncoding;

[15:11:37 CDT(-0500)] <EricDalquist> }

[15:11:51 CDT(-0500)] <EricDalquist> then the client would check both String and byte[]

[15:11:55 CDT(-0500)] <EricDalquist> and see which one isn't null

[15:12:00 CDT(-0500)] <EricDalquist> that would be good

[15:12:07 CDT(-0500)] <EricDalquist> since we could then also add things like status code

[15:12:08 CDT(-0500)] <EricDalquist> and headers

[15:12:12 CDT(-0500)] <EricDalquist> if those might be usful

[15:12:20 CDT(-0500)] <athena> oh i see - the issue is we're not sure if we're going to have a string or a bytestream?

[15:12:26 CDT(-0500)] <EricDalquist> right

[15:12:36 CDT(-0500)] <EricDalquist> you get a string if the rest API writes to response.getWriter()

[15:13:52 CDT(-0500)] <drewwills> no to which? (wink)

[15:13:53 CDT(-0500)] <EricDalquist> the only consideration on the Jackson stuff is how many exteral deps do we want?

[15:13:59 CDT(-0500)] <athena> yeah

[15:14:01 CDT(-0500)] <EricDalquist> no it isn't a problem, (smile)

[15:14:04 CDT(-0500)] <drewwills> good

[15:14:11 CDT(-0500)] <athena> it seems to me like it's probably not the end of the world to have just jackson as a dependency

[15:14:21 CDT(-0500)] <EricDalquist> well I'd go one step further

[15:14:22 CDT(-0500)] <athena> i guess i'd be more worried about relying heavily on particular spring versions?

[15:14:30 CDT(-0500)] <EricDalquist> I'd have two APIs a plain one

[15:14:35 CDT(-0500)] <EricDalquist> and a Spring 3 one

[15:17:06 CDT(-0500)] <EricDalquist> and that dictated the conversion

[15:17:28 CDT(-0500)] <EricDalquist> the HttpInputMessage interface is really simple

[15:17:39 CDT(-0500)] <EricDalquist> and we could create our own impl to wrap the captured output

[15:17:50 CDT(-0500)] <athena> ok yes, that completely makes sense

[15:17:56 CDT(-0500)] <EricDalquist> so "uportal-rest-api-portlet-client" would have:

[15:19:21 CDT(-0500)] <EricDalquist> RestResponse callPortalRestApi(PortletRequest, PortletResponse, String uri, Map<String, String[]> params)

[15:19:40 CDT(-0500)] <drewwills> btw I can certainly work on this vision in the context of my project... if we do it in a way in which I can also get some help from athena, that's even better

[15:20:19 CDT(-0500)] <EricDalquist> I would add this as a module in the uPortal project itself

[15:20:45 CDT(-0500)] <EricDalquist> then we add a BaseRequestPropertiesManager impl which exposes the portal's request context name as a portlet request property

[15:21:10 CDT(-0500)] <EricDalquist> to use callPortalRestApi in your portlet you would have to add the UPortalRestApiProxyServlet to the web.xml

[15:21:31 CDT(-0500)] <athena> do you mean create this as submodule of uportal or include the module in uportal's dependencies?

[15:22:57 CDT(-0500)] <EricDalquist> hrm

[15:23:05 CDT(-0500)] <drewwills> could we combine this utility with uportal-search-api? (though after maybe renaming it)

[15:23:06 CDT(-0500)] <EricDalquist> I was thinking as a submodule of uportal

[15:23:15 CDT(-0500)] <EricDalquist> though we need to move that search-api out too

[15:23:23 CDT(-0500)] <drewwills> yeah submodule b/c it's uP-specific

[15:23:24 CDT(-0500)] <athena> it might be eaiser to have it as a separate module

[15:23:25 CDT(-0500)] <EricDalquist> so maybe we actually get that jasig-portlet-utils going

[15:23:32 CDT(-0500)] <EricDalquist> and move the search api there

[15:23:35 CDT(-0500)] <EricDalquist> as well as this

[15:25:27 CDT(-0500)] <EricDalquist> then down the road we add another "uportal-rest-api-portlet-spring-client"

[15:25:33 CDT(-0500)] <EricDalquist> which depends on "uportal-rest-api-portlet-client"

[15:25:40 CDT(-0500)] <drewwills> seems like either (1) combine w/ search-api (2) move to jasig-portlet-utils or (3) both (smile)

[15:25:40 CDT(-0500)] <athena> sounds great to me

[15:26:09 CDT(-0500)] <EricDalquist> and adds:

[15:26:09 CDT(-0500)] <EricDalquist> T callPortalRestApi(PortletRequest, PortletResponse, String uri, Map<String, String[]> params, HttpMessageConverter<T>)

[15:29:00 CDT(-0500)] <athena> and we could improve it from there

[15:29:05 CDT(-0500)] <drewwills> i would probably leave moving the search api as a roadmap item, for the same of triage

[15:29:15 CDT(-0500)] <athena> i can help with some of this, but certainly not anytime in the next week

[15:29:17 CDT(-0500)] <EricDalquist> we don't

[15:29:24 CDT(-0500)] <EricDalquist> I had this working a while back locally

[15:29:27 CDT(-0500)] <athena> i don't think there's any direct relationship between this and the search module

[15:29:28 CDT(-0500)] <EricDalquist> but it never went anywhere

[15:33:39 CDT(-0500)] <drewwills> if I had this I could hit ANY rest api... not just ones I had made interfaces for

[15:33:40 CDT(-0500)] <EricDalquist> so designing a whole new API, implementation and way to provide it as a portal context attribute?

[15:33:42 CDT(-0500)] <athena> it sort of seems like most of the planning is already there? you'd just need to implement the steps eric already laid out

[15:33:46 CDT(-0500)] <EricDalquist> right

[15:34:00 CDT(-0500)] <athena> yes, you could hit any of the existing rest services

[15:34:08 CDT(-0500)] <athena> plus quickly attach to new ones you created

[15:34:14 CDT(-0500)] <drewwills> yeah I was picturing a "whole new API" of 1 interface, maybe 2 methods (wink)

[15:34:14 CDT(-0500)] <EricDalquist> this already exists: https://github.com/Jasig/portlet-utils

[15:34:15 CDT(-0500)] <athena> so if you needed a new service you could jsut add it to uportal and go

[15:34:33 CDT(-0500)] <EricDalquist> yes but it needs to be a well thought out API

[15:34:36 CDT(-0500)] <athena> so we just need a small library that's a submodule of portlet-utils

[15:34:38 CDT(-0500)] <athena> yes, it does

[15:38:06 CDT(-0500)] <drewwills> this is about getting all oars in the same boat, rowing the same way

[15:38:47 CDT(-0500)] <EricDalquist> right

[15:39:00 CDT(-0500)] <EricDalquist> so I thinkt he least effort is the rest api proxy code

[15:44:33 CDT(-0500)] <athena> also i think there's a really interesting use case for leveraging the uportal permissions framework for portlet use

[15:44:46 CDT(-0500)] <drewwills> yes, totally

[15:44:59 CDT(-0500)] <drewwills> need discoverable groups & so forth

[15:45:12 CDT(-0500)] <athena> could even create custom permissions

[15:45:12 CDT(-0500)] <drewwills> isUserInRole only goes so far (tongue)

[15:45:14 CDT(-0500)] <athena> yes.

[15:45:25 CDT(-0500)] <athena> things like the announcement portlet feed permissions could really use uportal permissions

[15:45:30 CDT(-0500)] <EricDalquist> so one thing we'll have to look into is overhead

[15:45:33 CDT(-0500)] <athena> would take some dev to get to that point, but i's possible

[16:16:53 CDT(-0500)] <drewwills> one more question EricDalquist – calling the rest api from a servlet (not portlet) not a problem, correct?

[16:17:28 CDT(-0500)] <EricDalquist> using the request dispatcher approach?

[16:19:00 CDT(-0500)] <drewwills> yeah

[16:19:13 CDT(-0500)] <EricDalquist> right

[16:19:18 CDT(-0500)] <drewwills> fewer steps even

[16:19:18 CDT(-0500)] <EricDalquist> that isn't a problem

[16:19:21 CDT(-0500)] <EricDalquist> right

[16:19:26 CDT(-0500)] <EricDalquist> it is the same as the portlet

[16:19:29 CDT(-0500)] <EricDalquist> just one less step

[16:19:50 CDT(-0500)] <drewwills> whereas the java api/portal context approach could require extra finessing

[16:21:38 CDT(-0500)] <EricDalquist> right

[16:21:44 CDT(-0500)] <EricDalquist> since the servlet has no context from the portal]

[16:47:09 CDT(-0500)] <drewwills> can you stuff GET/POST/PUT/DELETE into a requestDispatcher?

[16:47:38 CDT(-0500)] <EricDalquist> if you fake ity

[16:47:48 CDT(-0500)] <EricDalquist> with a custom HttpServletRequestWrapper

[16:49:57 CDT(-0500)] <EricDalquist> but doable

[16:55:15 CDT(-0500)]

<drewwills> so... any fancy Spring class to turn "/some/url/

Unknown macro: {p1}

?foo=

Unknown macro: {p2}

" into "/some/url/with?foo=

Unknown macro: {bar}

" given [ p1:with, p2:bar ]?

[16:55:41 CDT(-0500)] <athena> could take a look at the rest template source code

[16:55:47 CDT(-0500)] <athena> see if that's actually using another library

[16:58:48 CDT(-0500)] <athena> yeah

[16:58:54 CDT(-0500)] <athena> using an internal spring lib - UriTemplate

[17:10:40 CDT(-0500)] <athena> yes, i think we should use normal URL parameter behavior

[17:17:30 CDT(-0500)] <drewwills> sounds lovely... I thought I had seen that the getPeople() method expected differently, but I mis-remembered

[18:36:54 CDT(-0500)] <peterjhart> Here is a mockup of what a Fragment Manager UI could look like: https://wiki.jasig.org/display/UPC/uPortal+4+DLM+Fragment+Manager+Interface

  • No labels