Search in sources :

Example 6 with ActionMapping

use of org.springframework.web.portlet.bind.annotation.ActionMapping in project uPortal by Jasig.

the class SearchPortletController method performSearch.

@SuppressWarnings("unchecked")
@ActionMapping
public void performSearch(@RequestParam(value = "query") String query, ActionRequest request, ActionResponse response, @RequestParam(value = "ajax", required = false) final boolean ajax) throws IOException {
    final PortletSession session = request.getPortletSession();
    final String queryId = RandomStringUtils.randomAlphanumeric(32);
    Cache<String, Boolean> searchCounterCache;
    synchronized (org.springframework.web.portlet.util.PortletUtils.getSessionMutex(session)) {
        searchCounterCache = (Cache<String, Boolean>) session.getAttribute(SEARCH_COUNTER_NAME);
        if (searchCounterCache == null) {
            searchCounterCache = CacheBuilder.newBuilder().expireAfterAccess(1, TimeUnit.MINUTES).build();
            session.setAttribute(SEARCH_COUNTER_NAME, searchCounterCache);
        }
    }
    //Store the query id to track number of searches/minute
    searchCounterCache.put(queryId, Boolean.TRUE);
    if (searchCounterCache.size() > this.maximumSearchesPerMinute) {
        //Make sure old data is expired
        searchCounterCache.cleanUp();
        //Too many searches in the last minute, fail the search
        if (searchCounterCache.size() > this.maximumSearchesPerMinute) {
            logger.debug("Rejecting search for '{}', exceeded max queries per minute for user", query);
            if (!ajax) {
                response.setRenderParameter("hitMaxQueries", Boolean.TRUE.toString());
                response.setRenderParameter("query", query);
            } else {
                // For Ajax return to a nonexistent file to generate the 404 error since it was easier for the
                // UI to have an error response.
                final String contextPath = request.getContextPath();
                response.sendRedirect(contextPath + AJAX_MAX_QUERIES_URL);
            }
            return;
        }
    }
    // construct a new search query object from the string query
    final SearchRequest queryObj = new SearchRequest();
    queryObj.setQueryId(queryId);
    queryObj.setSearchTerms(query);
    // Create the session-shared results object
    final PortalSearchResults results = new PortalSearchResults(defaultTabKey, resultTypeMappings);
    // place the portal search results object in the session using the queryId to namespace it
    Cache<String, PortalSearchResults> searchResultsCache;
    synchronized (org.springframework.web.portlet.util.PortletUtils.getSessionMutex(session)) {
        searchResultsCache = (Cache<String, PortalSearchResults>) session.getAttribute(SEARCH_RESULTS_CACHE_NAME);
        if (searchResultsCache == null) {
            searchResultsCache = CacheBuilder.newBuilder().maximumSize(20).expireAfterAccess(5, TimeUnit.MINUTES).build();
            session.setAttribute(SEARCH_RESULTS_CACHE_NAME, searchResultsCache);
        }
        // Save the last queryId for an ajax autocomplete search response.
        session.setAttribute(SEARCH_LAST_QUERY_ID, queryId);
    }
    searchResultsCache.put(queryId, results);
    /*
         * TODO:  For autocomplete I wish we didn't have to go through a whole render phase just
         * to trigger the events-based features of the portlet, but atm I don't
         * see a way around it, since..
         *
         *   - (1) You can only start an event chain in the Action phase;  and
         *   - (2) You can only return JSON in a Resource phase;  and
         *   - (3) An un-redirected Action phase leads to a Render phase, not a
         *     Resource phase :(
         *
         * It would be awesome either (first choice) to do Action > Event > Resource,
         * or Action > sendRedirect() followed by a Resource request.
         *
         * As it stands, this implementation will trigger a complete render on
         * the portal needlessly.
         */
    // send a search query event
    response.setEvent(SearchConstants.SEARCH_REQUEST_QNAME, queryObj);
    logger.debug("Query initiated for queryId {}, query {}", queryId, query);
    response.setRenderParameter("queryId", queryId);
    response.setRenderParameter("query", query);
}
Also used : SearchRequest(org.apereo.portal.search.SearchRequest) PortletSession(javax.portlet.PortletSession) ActionMapping(org.springframework.web.portlet.bind.annotation.ActionMapping)

Aggregations

ActionMapping (org.springframework.web.portlet.bind.annotation.ActionMapping)6 TenantOperationResponse (org.apereo.portal.tenants.TenantOperationResponse)3 ArrayList (java.util.ArrayList)2 ITenant (org.apereo.portal.tenants.ITenant)2 HashSet (java.util.HashSet)1 PortletPreferences (javax.portlet.PortletPreferences)1 PortletSession (javax.portlet.PortletSession)1 WindowStateException (javax.portlet.WindowStateException)1 HttpServletRequest (javax.servlet.http.HttpServletRequest)1 IUserPreferencesManager (org.apereo.portal.IUserPreferencesManager)1 IUserLayout (org.apereo.portal.layout.IUserLayout)1 IUserLayoutManager (org.apereo.portal.layout.IUserLayoutManager)1 IUserLayoutNodeDescription (org.apereo.portal.layout.node.IUserLayoutNodeDescription)1 SearchRequest (org.apereo.portal.search.SearchRequest)1 ITenantManagementAction (org.apereo.portal.tenants.ITenantManagementAction)1 ITenantOperationsListener (org.apereo.portal.tenants.ITenantOperationsListener)1 IUserInstance (org.apereo.portal.user.IUserInstance)1