Jira Plugin: Dynamically Populating a Select Custom Field via Database - jira

I have been trying to make a Jira plugin using Java to try and make a SelectCFType get populated dynamically by using a database. I currently have a working SelectCFType from some code I found here. The only issue is I have no idea where to start when it comes to populating it via a database. I tried to manually populate it once, but Jira just gave me an error when creating a ticket because the stored values in its internal database for the Custom Field and the ones I provided were different. Any help would be greatly appreciated!
Java class
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.customfields.impl.SelectCFType;
import com.atlassian.jira.issue.customfields.manager.OptionsManager;
import com.atlassian.jira.issue.customfields.option.Option;
import com.atlassian.jira.issue.customfields.option.Options;
import com.atlassian.jira.issue.fields.config.FieldConfigScheme;
import com.atlassian.jira.issue.fields.rest.json.beans.JiraBaseUrls;
import com.atlassian.jira.issue.search.SearchContextImpl;
import org.apache.commons.collections.MultiMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.atlassian.jira.issue.customfields.manager.GenericConfigManager;
import com.atlassian.jira.issue.customfields.persistence.CustomFieldValuePersister;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.fields.config.FieldConfig;
import com.atlassian.jira.issue.fields.layout.field.FieldLayoutItem;
import com.atlassian.plugin.spring.scanner.annotation.imports.JiraImport;
import javax.inject.Inject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DynamicSelectCF extends SelectCFType{
private static final Logger log = LoggerFactory.getLogger(DynamicSelectCF.class);
private final OptionsManager optionsManager;
private final JiraBaseUrls jiraBaseUrls;
#Inject
public DynamicSelectCF(#JiraImport CustomFieldValuePersister customFieldValuePersister,
#JiraImport OptionsManager optionsManager,
#JiraImport GenericConfigManager genericConfigManager,
#JiraImport JiraBaseUrls jiraBaseUrls){
super(customFieldValuePersister, optionsManager, genericConfigManager, jiraBaseUrls);
this.optionsManager = optionsManager;
this.jiraBaseUrls = jiraBaseUrls;
}
#Override
public Map<String, Object> getVelocityParameters(final Issue issue,
final CustomField field,
final FieldLayoutItem fieldLayoutItem) {
final Map<String, Object> parameters = super.getVelocityParameters(issue, field, fieldLayoutItem);
FieldConfig fieldConfiguration = null;
if(issue == null)
{
fieldConfiguration = field.getReleventConfig(new SearchContextImpl());
} else
{
fieldConfiguration = field.getRelevantConfig(issue);
}
Options options = this.optionsManager.getOptions(fieldConfiguration);
if (options.isEmpty()) {
this.optionsManager.createOption(fieldConfiguration, null, new Long(1), "A");
this.optionsManager.createOption(fieldConfiguration, null, new Long(2), "B");
}
options = this.optionsManager.getOptions(fieldConfiguration);
Map<Long, String> results = new HashMap<Long, String>();
Long selectedId= (long) -1;
boolean selected = false;
Object value = field.getValue(issue);
if (value!=null) {
selected=true;
}
for (Option option : (Iterable<Option>) options) {
results.put(option.getOptionId(), option.getValue());
if (selected && value.toString().equals(option.getValue())) {
selectedId = option.getOptionId();
}
}
parameters.put("results", results);
parameters.put("selectedId", selectedId);
return parameters;
}
}
edit.vm (for web-resource)
#* #vtlvariable name="results" type="java.util.Map" *#
#* #vtlvariable name="selectedId" type="java.lang.String" *#
#controlHeader ($action $customField.id $customField.name $fieldLayoutItem.required $displayParameters.noHeader)
<select name="$customField.id" id="$customField.id" >
<option value="-1">Not selected</option>
#foreach ($mapEntry in $results.entrySet())
#if ( $selectedId == $mapEntry.key )
<option selected="selected" value="$mapEntry.key">$mapEntry.value</option>
#else
<option value="$mapEntry.key">$mapEntry.value</option>
#end
#end
</select>
#controlFooter ($action $fieldLayoutItem.fieldDescription $displayParameters.noHeader)

So I think I figured out a good way to do it. I created a method and so far it has been working very well.
public void populatingOprions(FieldConfig fieldConfiguration, ArrayList<String> optionPopulation){
for (int i = 0; i < population.size(); i++){
this.optionsManager.createOption(fieldConfiguration, null, new Long(i), optionPopulation.get(i));
}
hasBeenCalled = true;
}
In the getVelocityParameters method I added this code under the if(options.isEmpty()) statement
if(!hasBeenCalled) {
String arr[] = {"---------------", "This", "Is", "Just", "A", "Test", "For", "Population"};
for(int i = 0; i < arr.length; i++){
population.add(arr[i]);
}
populatingOprions(fieldConfiguration, population);
}
I have an ArrayList that hold all the values and I think we have a mySQL database wich appears to be pretty easy to get the data from. hasBeenCalled is a boolean that tracks if the method got called already to populate the SelectCF's options so it doesn't duplicate them.

Not to discourage you at all from enjoying writing the Jira plugin, but there are few other options
https://marketplace.atlassian.com/apps/23337/elements-connect-external-data-fields?hosting=cloud&tab=overview
You can also write scripts to do this with ScriptRunner
We use the second approach to populate a single-line text field with data from an company REST API. It feels like using a type-ahead field such as components.

Related

Integrate KoliBri web-components in Vaadin

I am trying to integrate KoliBri web-components (https://github.com/public-ui/kolibri) in a Vaadin project. I followed the documentation for web components integration (https://vaadin.com/docs/latest/create-ui/web-components) but I was not successful.
I want to integrate a KoliBri-button (kol-button) and therefor created getter and setter methods for the required properties of the button. When loading the website, the kol-button-component is loaded successfully from the .js file.
enter image description here
But the kol-button element in the DOM is empty and won´t show up:
enter image description here
Here is my KolButton.java:
package com.example.application.views.helloworld;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Synchronize;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.dependency.NpmPackage;
#Tag("kol-button")
#NpmPackage(value = "#public-ui/components", version = "1.1.10")
#JsModule("#public-ui/components/dist/components/kol-button")
public class KolButton extends Component {
public boolean getLabel() {
return getElement().getProperty("_label", false);
}
public void setLabel(String label) {
getElement().setProperty("_label", label);
}
public void setVariant(String variant) {
getElement().setProperty("_variant", variant);
}
public boolean getVariant() {
return getElement().getProperty("_variant", false);
}
}
And the view.java:
package com.example.application.views.helloworld;
import com.example.application.views.MainLayout;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.RouteAlias;
#PageTitle("Hello World")
#Route(value = "hello", layout = MainLayout.class)
#RouteAlias(value = "", layout = MainLayout.class)
public class HelloWorldView extends HorizontalLayout {
public HelloWorldView() {
var kolButton = new KolButton();
kolButton.setLabel("TestText");
kolButton.setVariant("danger");
setVerticalComponentAlignment(Alignment.END, kolButton);
add(kolButton);
}
}
Do you have any idea to solve this? Thanks in advance

Xtext: Calling the Generator from a Context Menu

Following
https://christiandietrich.wordpress.com/2011/10/15/xtext-calling-the-generator-from-a-context-menu/
and using EclipseResourceFileSystemAccess2 instead of EclipseResourceFileSystemAccess when the line
final EclipseResourceFileSystemAccess2 fsa = fileAccessProvider.get();
give an exception. The only information I have is
// Compiled from InvocationTargetException.java (version 1.8 : 52.0, super bit)
public class java.lang.reflect.InvocationTargetException extends java.lang.ReflectiveOperationException {
I don't know how to get the stack trace in Eclipse.
does the code in the blog still function in the most recent release of Xtext?
Update 1
Snippets from plugin.xml
Handler:
<extension
point="org.eclipse.ui.handlers">
<handler
class="tuks.mcrl2.dsl.ui.handlers.Mcrl22Lps"
commandId="tuks.mcrl2.dsl.ui.commands.mcrl2lps">
</handler>
</extension>
Commands:
<extension
point="org.eclipse.ui.commands">
<command
categoryId="tuks.mcrl2.dsl.ui.category.processalgebra"
defaultHandler="tuks.mcrl2.dsl.ui.handlers.Mcrl22Lps"
description="Conver a mclr2 file to lps"
id="tuks.mcrl2.dsl.ui.commands.mcrl2lps"
name="mcrl22lps">
</command>
<category
id="tuks.mcrl2.dsl.ui.category.processalgebra"
name="Process Algebra">
</category>
</extension>
it basically works, if you do the update from EclipseResourceFileSystemAccess and Stuff and (maybe) IGenerator.
I assume in your case you dont set the Accesses ProgressMonitor and other props.
package org.xtext.example.mydsl.ui.handler;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.xtext.builder.EclipseResourceFileSystemAccess2;
import org.eclipse.xtext.generator.GeneratorContext;
import org.eclipse.xtext.generator.IGenerator2;
import org.eclipse.xtext.resource.IResourceDescriptions;
import org.eclipse.xtext.ui.resource.IResourceSetProvider;
import com.google.inject.Inject;
import com.google.inject.Provider;
public class GenerationHandler extends AbstractHandler implements IHandler {
#Inject
private IGenerator2 generator;
#Inject
private Provider<EclipseResourceFileSystemAccess2> fileAccessProvider;
#Inject
IResourceDescriptions resourceDescriptions;
#Inject
IResourceSetProvider resourceSetProvider;
#Override
public Object execute(ExecutionEvent event) throws ExecutionException {
ISelection selection = HandlerUtil.getCurrentSelection(event);
if (selection instanceof IStructuredSelection) {
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
Object firstElement = structuredSelection.getFirstElement();
if (firstElement instanceof IFile) {
IFile file = (IFile) firstElement;
IProject project = file.getProject();
IFolder srcGenFolder = project.getFolder("src-gen");
if (!srcGenFolder.exists()) {
try {
srcGenFolder.create(true, true,
new NullProgressMonitor());
} catch (CoreException e) {
return null;
}
}
final EclipseResourceFileSystemAccess2 fsa = fileAccessProvider.get();
fsa.setProject(project);
fsa.setOutputPath("src-gen");
fsa.setMonitor(new NullProgressMonitor());
URI uri = URI.createPlatformResourceURI(file.getFullPath().toString(), true);
ResourceSet rs = resourceSetProvider.get(project);
Resource r = rs.getResource(uri, true);
generator.doGenerate(r, fsa, new GeneratorContext());
}
}
return null;
}
#Override
public boolean isEnabled() {
return true;
}
}
and make sure you register the handler properly.
the
class="org.xtext.example.mydsl.ui.MyDslExecutableExtensionFactory:org.xtext.example.mydsl.ui.handler.GenerationHandler"
is crucial, especially that it consists of 2 parts, the ExtensionFactory followed by a : followed by the actual class name

Posting to a REST API on form submit with Orbeon

I am looking through the documentation for a sample of how to handle a submit from an Orbeon form that I gather some data in and then submitting to another application via REST. I am not seeing anything that shows how to do that. Does Orbeon provide functionality to do that or do I need to code some JSP or something else on the backside to handle that?
My understanding is, that you have to provide/implement the REST service yourself. You aren't restricted to do it in Java, but if this is your preferred language, here's how a very simple servlet would look like. In this case the REST service saves the form in a file in the temp directory.
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Optional;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FormDumpServlet extends HttpServlet {
private static final Logger logger = Logger.getLogger(FormDumpServlet.class.getName());
private static final SimpleDateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS");
protected Optional<String> makeTempDir() {
final String dir = System.getProperty("java.io.tmpdir");
logger.info(String.format("java.io.tmpdir=%s", dir));
if (dir == null) {
logger.severe("java.io.tmpdir is null, can't create temp directory");
return Optional.empty();
}
final File f = new File(dir,"form-dumps");
if (f.exists() && f.isDirectory() && f.canWrite()) {
return Optional.of(f.getAbsolutePath());
}
if (f.mkdir()) {
return Optional.of(f.getAbsolutePath());
}
logger.severe(String.format("failed to create temp dir <%s>", f.getAbsolutePath()));
return Optional.empty();
}
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String path = req.getPathInfo();
if (!path.equalsIgnoreCase("/accept-form")) {
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
Enumeration<String> parameterNames = req.getParameterNames();
while(parameterNames.hasMoreElements()) {
final String name = parameterNames.nextElement();
final String value = req.getParameter(name);
logger.info(String.format("parameter: name=<%s>, value=<%s>", name, value));
}
Optional<String> tempPath = makeTempDir();
if (tempPath.isPresent()) {
String fn = String.format("%s.xml", FORMAT.format(new Date()));
File f = new File(new File(tempPath.get()), fn);
logger.info(String.format("saving form to file <%s>", f.getAbsolutePath()));
try(PrintWriter pw = new PrintWriter(new FileWriter(f))) {
req.getReader().lines().forEach((l) -> pw.println(l));
}
}
resp.setStatus(HttpServletResponse.SC_OK);
}
}
You also have to configure a property in properties-local.xml which connects the send action for your form (the form with the name my_form in your application my_application) to the REST endpoint. This property could look as follows:
<property
as="xs:string"
name="oxf.fr.detail.process.send.my_application.my_form"
>
require-valid
then save-final
then send(uri = "http://localhost:8080/my-form-dump-servlet/accept-form")
then success-message(message = "Success: the form was transferred to the REST service")
</property>

Spring Data Neo4j and entity being #RelatedTo in collection and in other entity - relationship not created

Today I was struggling with SDN and my model.
Basically what I want to achieve is to have Foo entity relation to Bar entites but also I need to keep nextBar relation in each Bar entity to easily check some properties of nextBar (Bars are ordered).
I wanted to achieve this by using :
package neo4j.example.domain;
import org.springframework.data.neo4j.annotation.Fetch;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.RelatedTo;
import java.util.HashSet;
import java.util.Set;
#NodeEntity
public class Foo {
#GraphId
public Long id;
#Fetch
#RelatedTo
public Set<Bar> bars = new HashSet<>();
#Override
public String toString() {
return "Foo{" +
"id=" + id +
", bars=" + bars +
'}';
}
}
and
package neo4j.example.domain;
import org.springframework.data.neo4j.annotation.Fetch;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.RelatedTo;
#NodeEntity
public class Bar {
#GraphId
public Long id;
#Fetch
#RelatedTo
public Bar nextBar;
#Override
public String toString() {
return "Bar{" +
"id=" + id +
", nextBar=" + nextBar +
'}';
}
}
but I encountered problem in my project unit tests (some of them didn't pass). After some investigation I discovered that if I persist the data in one go:
public class AllInOneTest {
ApplicationContext context = new AnnotationConfigApplicationContext(ExampleNeo4jConfiguration.class);
GraphDatabaseService graphDatabaseService = context.getBean(GraphDatabaseService.class);
Neo4jOperations neo4jOperations = context.getBean(Neo4jOperations.class);
FooRepository fooRepository = context.getBean(FooRepository.class);
ExecutionEngine executionEngine = new ExecutionEngine(graphDatabaseService);
#Before
public void setUp(){
executionEngine.execute(CLEAN_DATABASE_QUERY);
}
#Test
public void shouldProperlyCreateRelationships(){
// given
Bar firstBar = new Bar();
Bar secondBar = new Bar();
Foo foo = new Foo();
firstBar.nextBar = secondBar;
foo.bars.addAll(Arrays.asList(firstBar, secondBar));
// when
fooRepository.save(foo);
// then
Foo retrievedFoo = fooRepository.findOne(foo.id);
System.out.println(retrievedFoo);
for(Bar bar: retrievedFoo.bars) {
if(firstBar.id.equals(bar.id)){
Assert.assertNotNull(bar.nextBar);
}
}
}
}
I get
Foo{id=0, bars=[Bar{id=2, nextBar=Bar{id=1, nextBar=null}}, Bar{id=1, nextBar=null}]}
from my System.out.println so everything persisted the way I wanted.
But usually I am not getting all Bars in one go (user adds one Bar and after 5 minutes user adds second Bar) - and here is the problem.
package neo4j.example;
import neo4j.example.configuration.ExampleNeo4jConfiguration;
import neo4j.example.domain.Bar;
import neo4j.example.domain.Foo;
import neo4j.example.repository.FooRepository;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.neo4j.cypher.javacompat.ExecutionEngine;
import org.neo4j.graphdb.GraphDatabaseService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.Arrays;
import static neo4j.example.repository.Query.CLEAN_DATABASE_QUERY;
public class OneByOneTest {
ApplicationContext context = new AnnotationConfigApplicationContext(ExampleNeo4jConfiguration.class);
GraphDatabaseService graphDatabaseService = context.getBean(GraphDatabaseService.class);
FooRepository fooRepository = context.getBean(FooRepository.class);
ExecutionEngine executionEngine = new ExecutionEngine(graphDatabaseService);
#Before
public void setUp(){
executionEngine.execute(CLEAN_DATABASE_QUERY);
}
#Test
public void shouldProperlyCreateRelationships(){
// given
Bar firstBar = new Bar();
Foo foo = new Foo();
foo.bars.add(firstBar);
fooRepository.save(foo);
// when
Bar secondBar = new Bar();
Foo firstRetrievedFoo = fooRepository.findOne(foo.id);
Bar[] bars = firstRetrievedFoo.bars.toArray(new Bar[0]);
bars[0].nextBar = secondBar;
firstRetrievedFoo.bars.add(secondBar);
System.out.println(firstRetrievedFoo);
fooRepository.save(firstRetrievedFoo);
System.out.println(firstRetrievedFoo);
// then
// then
Foo retrievedFoo = fooRepository.findOne(foo.id);
System.out.println(retrievedFoo);
for(Bar bar: retrievedFoo.bars) {
if(firstBar.id.equals(bar.id)){
Assert.assertNotNull(bar.nextBar);
}
}
}
}
This code on empty database prints:
Foo{id=125130, bars=[Bar{id=125131, nextBar=Bar{id=null, nextBar=null}}, Bar{id=null, nextBar=null}]}
Foo{id=125130, bars=[Bar{id=125131, nextBar=Bar{id=125132, nextBar=null}}, Bar{id=125132, nextBar=null}]}
Foo{id=125130, bars=[Bar{id=125132, nextBar=null}, Bar{id=125131, nextBar=null}]}
And the test fails. I can see that before and after persisting the relationship to new nextBar is pointing where I want it to. After retrieving Foo from the repository it is set to null.
Here is the example project: https://github.com/Adebski/neo4j-relatedto-problem/
I am using simple mapping and embedded version of Neo4j. Advanced mapping is currently not an option for me because my normal project is in Scala with SBT and AFAIK this combination with SDN advanced mapping does not work.
Have tried issuing save(firstBar) separately (after setting nextBar on it) to see if that helps? It might be that the cascading save doesn't work the way you think - i.e. I know it will persist any detached entities but I wouldn't be surprised if it wasn't updating all the properties/relationship of already existing nodes. Generally speaking if I remember correctly by default the #RelatedTo only retrieves the id of the connected nodes, unless it's annotated with #Fetch. Therefore, I don't think it would have an easy way of determining that you added a relationship to it, or changed a property.

Run JesterRecommenderEvaluationRunner, but get no results of evaluation

I downloaded the Jester example code in Mahout, and tries to run it on jester dataset to see the evaluation results. the running is done successfully, but the console only has the results:
log4j:WARN No appenders could be found for logger (org.apache.mahout.cf.taste.impl.model.file.FileDataModel).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
I expect to see the evaluation score range from 0 to 10. any one can help me found out how to get the score?
I am using mahout-core-0.6.jar and the following is the code:
JesterDataModel.java:
package Jester;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.regex.Pattern;
import com.google.common.collect.Lists;
import org.apache.mahout.cf.taste.example.grouplens.GroupLensDataModel;
import org.apache.mahout.cf.taste.impl.common.FastByIDMap;
import org.apache.mahout.cf.taste.impl.model.GenericDataModel;
import org.apache.mahout.cf.taste.impl.model.GenericPreference;
import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.model.Preference;
import org.apache.mahout.common.iterator.FileLineIterator;
//import org.apache.mahout.cf.taste.impl.common.FileLineIterable;
public final class JesterDataModel extends FileDataModel {
private static final Pattern COMMA_PATTERN = Pattern.compile(",");
private long userBeingRead;
public JesterDataModel() throws IOException {
this(GroupLensDataModel.readResourceToTempFile("\\jester-data-1.csv"));
}
public JesterDataModel(File ratingsFile) throws IOException {
super(ratingsFile);
}
#Override
public void reload() {
userBeingRead = 0;
super.reload();
}
#Override
protected DataModel buildModel() throws IOException {
FastByIDMap<Collection<Preference>> data = new FastByIDMap<Collection<Preference>> ();
FileLineIterator iterator = new FileLineIterator(getDataFile(), false);
FastByIDMap<FastByIDMap<Long>> timestamps = new FastByIDMap<FastByIDMap<Long>>();
processFile(iterator, data, timestamps, false);
return new GenericDataModel(GenericDataModel.toDataMap(data, true));
}
#Override
protected void processLine(String line,
FastByIDMap<?> rawData,
FastByIDMap<FastByIDMap<Long>> timestamps,
boolean fromPriorData) {
FastByIDMap<Collection<Preference>> data = (FastByIDMap<Collection<Preference>>) rawData;
String[] jokePrefs = COMMA_PATTERN.split(line);
int count = Integer.parseInt(jokePrefs[0]);
Collection<Preference> prefs = Lists.newArrayListWithCapacity(count);
for (int itemID = 1; itemID < jokePrefs.length; itemID++) { // yes skip first one, just a count
String jokePref = jokePrefs[itemID];
if (!"99".equals(jokePref)) {
float jokePrefValue = Float.parseFloat(jokePref);
prefs.add(new GenericPreference(userBeingRead, itemID, jokePrefValue));
}
}
data.put(userBeingRead, prefs);
userBeingRead++;
}
}
JesterRecommenderEvaluatorRunner.java
package Jester;
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.eval.RecommenderEvaluator;
import org.apache.mahout.cf.taste.impl.eval.AverageAbsoluteDifferenceRecommenderEvaluator;
import org.apache.mahout.cf.taste.model.DataModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
public final class JesterRecommenderEvaluatorRunner {
private static final Logger log = LoggerFactory.getLogger(JesterRecommenderEvaluatorRunner.class);
private JesterRecommenderEvaluatorRunner() {
// do nothing
}
public static void main(String... args) throws IOException, TasteException {
RecommenderEvaluator evaluator = new AverageAbsoluteDifferenceRecommenderEvaluator();
DataModel model = new JesterDataModel();
double evaluation = evaluator.evaluate(new JesterRecommenderBuilder(),
null,
model,
0.9,
1.0);
log.info(String.valueOf(evaluation));
}
}
Mahout 0.7 is old, and 0.6 is very old. Use at least 0.7, or better, later from SVN.
I think the problem is exactly what you identified: you don't have any slf4j bindings in your classpath. If you use the ".job" files in Mahout you will have all dependencies packages. Then you will actually see output.

Resources