001package org.deepamehta.plugins.littlehelpers;
002
003import de.deepamehta.core.RelatedTopic;
004import java.util.logging.Logger;
005import java.util.List;
006
007import javax.ws.rs.GET;
008import javax.ws.rs.Path;
009import javax.ws.rs.PathParam;
010import javax.ws.rs.Produces;
011import javax.ws.rs.Consumes;
012
013import de.deepamehta.core.Topic;
014import de.deepamehta.core.TopicType;
015
016import de.deepamehta.core.osgi.PluginActivator;
017import de.deepamehta.core.service.Inject;
018import de.deepamehta.plugins.workspaces.WorkspacesService;
019import java.util.ArrayList;
020import javax.ws.rs.core.MediaType;
021
022
023/**
024 * @author Malte Reißig (<malte@mikromedia.de>)
025 * @website http://github.com/mukil/dm4-littlehelpers
026 * @version 0.1.0 - compatible with DeepaMehta 4.5
027 *
028 */
029
030@Path("/helpers")
031@Consumes(MediaType.APPLICATION_JSON)
032@Produces(MediaType.APPLICATION_JSON)
033public class LittleHelpersPlugin extends PluginActivator implements LittleHelpersService {
034
035    private Logger log = Logger.getLogger(getClass().getName());
036
037    // --- DeepaMehta Standard URIs
038
039    /** private final static String CHILD_URI = "dm4.core.child";
040    private final static String PARENT_URI = "dm4.core.parent";
041    private final static String AGGREGATION = "dm4.core.aggregation"; **/
042
043    @Inject WorkspacesService wsService;
044    
045    @GET
046    @Override
047    @Path("/suggest/topics/{input}")
048    public List<SuggestionViewModel> getTopicSuggestions(@PathParam("input") String query) {
049        if(query == null || query.length() < 2) throw new IllegalArgumentException("To receive "
050                + "suggestions, please provide at least two characters.");
051        List<SuggestionViewModel> suggestions = new ArrayList<SuggestionViewModel>();
052        // three explicit search for topicmap name, usernames and note-titles ### add IndexMode.FULLTEXT_KEY ?
053        List<Topic> results = getTopicSuggestions(query, "dm4.topicmaps.name");
054        results.addAll(getTopicSuggestions(query, "dm4.notes.title"));
055        results.addAll(getTopicSuggestions(query, "dm4.accesscontrol.username"));
056        // append the results of a generic fulltext search
057        List<Topic> naives = dms.searchTopics(query + "*", null);
058        if (naives != null) {
059            log.info("Naive search " + naives.size() + " length");
060            results.addAll(naives);
061        }
062        // 
063        log.info("> Checking for searchable units.. in " + results.size() );
064        List<Topic> new_results = findSearchableUnits(results);
065        for (Topic t : new_results) {
066            log.fine("Suggesting \"" + t.getSimpleValue() + "\" topics (workspace=" + wsService.getAssignedWorkspace(t.getId())+ ")");
067            suggestions.add(new SuggestionViewModel(t, wsService.getAssignedWorkspace(t.getId())));
068        }
069        log.info("Suggesting " + suggestions.size() + " topics for input: " + query);
070        return suggestions;
071    }
072    
073    @GET
074    @Override
075    @Path("/suggest/topics/{input}/{typeUri}")
076    public List<Topic> getTopicSuggestions(@PathParam("input") String query, 
077            @PathParam("typeUri") String typeUri) {
078        return dms.searchTopics(query + "*", typeUri);
079    }
080
081    // --
082    // --- Helper Methods taken from the WebclientPlugin.java by Jörg Richter
083    // --
084
085    private List<Topic> findSearchableUnits(List<? extends Topic> topics) {
086        List<Topic> searchableUnits = new ArrayList<Topic>();
087        for (Topic topic : topics) {
088            if (searchableAsUnit(topic)) {
089                searchableUnits.add(topic);
090            } else {
091                List<RelatedTopic> parentTopics = topic.getRelatedTopics((String) null, "dm4.core.child",
092                    "dm4.core.parent", null, 0).getItems();
093                if (parentTopics.isEmpty()) {
094                    searchableUnits.add(topic);
095                } else {
096                    searchableUnits.addAll(findSearchableUnits(parentTopics));
097                }
098            }
099        }
100        return searchableUnits;
101    }
102
103    private boolean searchableAsUnit(Topic topic) {
104        TopicType topicType = dms.getTopicType(topic.getTypeUri());
105        Boolean searchableAsUnit = (Boolean) getViewConfig(topicType, "searchable_as_unit");
106        return searchableAsUnit != null ? searchableAsUnit.booleanValue() : false;  // default is false
107    }
108
109    /**
110     * Read out a view configuration setting.
111     * <p>
112     * Compare to client-side counterpart: function get_view_config() in webclient.js
113     *
114     * @param   topicType   The topic type whose view configuration is read out.
115     * @param   setting     Last component of the setting URI, e.g. "icon".
116     *
117     * @return  The setting value, or <code>null</code> if there is no such setting
118     */
119    private Object getViewConfig(TopicType topicType, String setting) {
120        return topicType.getViewConfig("dm4.webclient.view_config", "dm4.webclient." + setting);
121    }
122
123}