Add AccountPermission

This commit is contained in:
steve 2013-10-08 12:17:26 +08:00
parent 283766c0c2
commit dbe34cf468
21 changed files with 2329 additions and 111 deletions

View File

@ -1,13 +1,17 @@
package com.pmease.gitop.web;
import java.util.Set;
import javax.inject.Singleton;
import com.codahale.dropwizard.jackson.Jackson;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Provides;
import com.pmease.commons.jetty.ServletConfigurator;
import com.pmease.commons.loader.AbstractPluginModule;
import com.pmease.commons.wicket.AbstractWicketConfig;
import com.pmease.gitop.core.validation.ProjectNameReservation;
import com.pmease.gitop.core.validation.UserNameReservation;
import com.pmease.gitop.web.resource.RestResourceModule;
@ -29,8 +33,32 @@ public class WebModule extends AbstractPluginModule {
contribute(UserNameReservation.class, WebUserNameReservation.class);
install(new RestResourceModule());
contribute(ProjectNameReservation.class, DefaultProjectNameReservation.class);
contribute(UserNameReservation.class, DefaultUserNameReservation.class);
}
public static class DefaultProjectNameReservation implements ProjectNameReservation {
@Override
public Set<String> getReserved() {
return ImmutableSet.<String>of(
);
}
}
public static class DefaultUserNameReservation implements UserNameReservation {
@Override
public Set<String> getReserved() {
return ImmutableSet.<String>of(
"rest",
"assets"
);
}
}
@Provides
@Singleton
public ObjectMapper objectMapper() {

View File

@ -332,8 +332,6 @@ a > .icon-null, .icon-null { display: inline-block; width: 10px; }
section .head { border-style: solid; border-width: 1px 0; border-color: #ddd; }
section:first-child .head { border-top: none; }
.content .head h3 { margin: 0; font-size: 18px; line-height: 24px; color: #888; font-weight: 300; }
.content .padder { padding: 0px 20px 20px; margin-bottom: 18px; }
.content .padder:nth-child(1) { padding-top: 0; }
section .head h2, section .head h3 { margin: 0; font-size: 18px; line-height: 24px; color: #888; font-weight: 300; }
section .padder, section > .body { padding: 0px 20px 20px; margin-bottom: 18px; }

View File

@ -0,0 +1,31 @@
package com.pmease.gitop.web.common.component.datagrid;
import java.util.List;
import org.apache.wicket.event.IEvent;
import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.markup.repeater.data.IDataProvider;
import com.pmease.gitop.web.common.component.datagrid.event.PageChanged;
@SuppressWarnings("serial")
public class DataGrid<T> extends DataTable<T, String>{
public DataGrid(String id, List<? extends IColumn<T, String>> columns,
IDataProvider<T> dataProvider, long rowsPerPage) {
super(id, columns, dataProvider, rowsPerPage);
setOutputMarkupId(true);
setVersioned(false);
}
@Override
public void onEvent(IEvent<?> event) {
if (event.getPayload() instanceof PageChanged) {
PageChanged payload = (PageChanged) event.getPayload();
setCurrentPage(payload.getPage());
payload.getTarget().add(this);
}
}
}

View File

@ -0,0 +1,19 @@
package com.pmease.gitop.web.common.component.datagrid.event;
import org.apache.wicket.ajax.AjaxRequestTarget;
import com.pmease.gitop.web.common.event.AjaxEvent;
public class PageChanged extends AjaxEvent {
private final int page;
public PageChanged(AjaxRequestTarget target, int page) {
super(target);
this.page = page;
}
public int getPage() {
return page;
}
}

View File

@ -0,0 +1,19 @@
package com.pmease.gitop.web.common.component.datagrid.event;
import org.apache.wicket.ajax.AjaxRequestTarget;
import com.pmease.gitop.web.common.event.AjaxEvent;
public class SearchStringChanged extends AjaxEvent {
private final String pattern;
public SearchStringChanged(AjaxRequestTarget target, String pattern) {
super(target);
this.pattern = pattern;
}
public String getPattern() {
return pattern;
}
}

View File

@ -0,0 +1,59 @@
package com.pmease.gitop.web.common.component.datagrid.hibernate;
import java.util.Iterator;
import java.util.List;
import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
import org.apache.wicket.model.IModel;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import com.google.common.base.Splitter;
import com.pmease.commons.hibernate.AbstractEntity;
import com.pmease.commons.hibernate.dao.GeneralDao;
import com.pmease.commons.loader.AppLoader;
import com.pmease.gitop.web.model.EntityModel;
public abstract class HibernateDataProvider<T extends AbstractEntity> extends SortableDataProvider<T, String> {
private static final long serialVersionUID = 9007657871051510330L;
abstract protected DetachedCriteria getCriteria();
protected GeneralDao getDao() {
return AppLoader.getInstance(GeneralDao.class);
}
@Override
public Iterator<? extends T> iterator(long first, long count) {
GeneralDao dao = getDao();
DetachedCriteria criteria = getCriteria();
SortParam<String> param = getSort();
if (param != null) {
DetachedCriteria crit = getCriteria();
Iterable<String> it = Splitter.on(",").trimResults().split(param.getProperty());
for (String each : it) {
if (param.isAscending())
crit.addOrder(Order.asc(each));
else
crit.addOrder(Order.desc(each));
}
}
@SuppressWarnings("unchecked")
List<T> list = (List<T>) dao.query(criteria, (int) first, (int) count);
return list.iterator();
}
@Override
public long size() {
GeneralDao dao = getDao();
return dao.count(getCriteria());
}
@Override
public IModel<T> model(T object) {
return new EntityModel<T>(object);
}
}

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html xmlns:wicket="http://wicket.apache.org">
<body>
<wicket:panel>
<ul class="pagination pagination-sm">
<li><a wicket:id="first" class="first"><i class="icon-double-angle-left"></i></a></li>
<li><a wicket:id="prev"><i class="icon-angle-left"></i></a></li>
<wicket:container wicket:id="navigation">
<li><a wicket:id="pageLink" href="#"><span wicket:id="pageNumber">5</span></a></li>
</wicket:container>
<li><a wicket:id="next"><i class="icon-angle-right"></i></a></li>
<li><a wicket:id="last" class="last"><i class="icon-double-angle-right"></i></a></li>
</ul>
</wicket:panel>
</body>
</html>

View File

@ -0,0 +1,17 @@
package com.pmease.gitop.web.common.component.datagrid.toolbar;
import org.apache.wicket.markup.html.navigation.paging.IPageable;
import org.apache.wicket.markup.html.navigation.paging.IPagingLabelProvider;
public class AjaxPagingNavigator extends org.apache.wicket.ajax.markup.html.navigation.paging.AjaxPagingNavigator {
private static final long serialVersionUID = 1L;
public AjaxPagingNavigator(String id, IPageable pageable) {
super(id, pageable);
}
public AjaxPagingNavigator(final String id, final IPageable pageable,
final IPagingLabelProvider labelProvider) {
super(id, pageable, labelProvider);
}
}

View File

@ -0,0 +1,35 @@
<html xmlns:wicket>
<wicket:panel>
<tr class="search-nav-tr">
<td wicket:id="td" class="search-nav-td">
<div class="clearfix">
<div class="pull-left" wicket:id="search"></div>
<div class="pull-right" wicket:id="nav"></div>
</div>
</td>
</tr>
<wicket:fragment wicket:id="searchFrag">
<form class="form-inline search-form" wicket:id="searchForm">
<input type="text" class="form-control input-sm" wicket:id="input" />
<button type="button" class="search-icon" wicket:id="submit"><i class="icon-search"></i></button>
</form>
</wicket:fragment>
<wicket:fragment wicket:id="navFrag">
<form class="form-inline navigation-form" wicket:id="form">
<span>Show rows:</span>
<select class="form-control input-sm" wicket:id="rowsSelector"></select>
<span>Go to:</span>
<input class="form-control input-sm" type="text" value="1" autocomplete="off" wicket:id="pageInput" />
<span wicket:id="navlabel"></span>
<div class="btn-group">
<a class="btn btn-default btn-xs" wicket:id="previousLink"><i class="icon-chevron-left"></i></a>
<a class="btn btn-default btn-xs" wicket:id="nextLink"><i class="icon-chevron-right"></i></a>
</div>
<input type="hidden" value="go" wicket:id="submit" />
</form>
</wicket:fragment>
</wicket:panel>
</html>

View File

@ -0,0 +1,232 @@
package com.pmease.gitop.web.common.component.datagrid.toolbar;
import java.util.List;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.event.Broadcast;
import org.apache.wicket.event.IEvent;
import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractToolbar;
import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.PropertyModel;
import com.google.common.collect.ImmutableList;
import com.pmease.gitop.web.common.component.datagrid.event.PageChanged;
import com.pmease.gitop.web.common.component.datagrid.event.SearchStringChanged;
public class SearchNavToolbar extends AbstractToolbar {
private static final long serialVersionUID = 1L;
public SearchNavToolbar(DataTable<?, ?> table) {
super(table);
setOutputMarkupId(true);
}
@Override
protected void onInitialize() {
super.onInitialize();
WebMarkupContainer span = new WebMarkupContainer("td");
add(span);
span.add(AttributeModifier.replace("colspan", new AbstractReadOnlyModel<String>() {
private static final long serialVersionUID = 1L;
@Override
public String getObject() {
return String.valueOf(getTable().getColumns().size());
}
}));
span.add(newSearchForm("search"));
span.add(newNavigationForm("nav"));
}
@Override
protected void onConfigure() {
super.onConfigure();
this.setVisibilityAllowed(getTable().getRowCount() > 0);
}
protected Component newSearchForm(String id) {
Fragment frag = new Fragment(id, "searchFrag", this);
frag.add(new SearchForm("searchForm"));
return frag;
}
@SuppressWarnings({"serial"})
private class SearchForm extends Form<Void> {
private String pattern;
public SearchForm(String id) {
super(id);
}
@Override
protected void onInitialize() {
super.onInitialize();
TextField<String> input = new TextField<String>("input", new PropertyModel<String>(this, "pattern"));
add(input);
IndicatingAjaxButton submit = new IndicatingAjaxButton("submit", this) {
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
send(getTable(), Broadcast.BREADTH, new SearchStringChanged(target, pattern));
}
};
add(submit);
setDefaultButton(submit);
}
@Override
public void onEvent(IEvent<?> event) {
if (event.getPayload() instanceof SearchStringChanged) {
SearchStringChanged e = (SearchStringChanged) event.getPayload();
this.pattern = e.getPattern();
e.getTarget().add(this);
}
}
}
protected void onPageChanged(AjaxRequestTarget target) {
target.add(getTable());
target.add(this);
}
protected Component newNavigationForm(String id) {
Fragment frag = new Fragment(id, "navFrag", this);
frag.add(new NavigationForm("form"));
return frag;
}
static final List<Integer> ROWS_PER_PAGE = ImmutableList.<Integer>of(10, 25, 50, 100, 250, 500);
@SuppressWarnings({"serial"})
private class NavigationForm extends Form<Void> {
private int rowsPerPage = 10;
private int currentPage = 1;
public NavigationForm(String id) {
super(id);
}
@Override
protected void onInitialize() {
super.onInitialize();
DropDownChoice<Integer> rowsSelector = new DropDownChoice<Integer>("rowsSelector",
new PropertyModel<Integer>(this, "rowsPerPage"), ROWS_PER_PAGE);
add(rowsSelector);
rowsSelector.add(new AjaxFormComponentUpdatingBehavior("onchange") {
@Override
protected void onUpdate(AjaxRequestTarget target) {
currentPage = 1;
getTable().setItemsPerPage(rowsPerPage);
send(getTable(), Broadcast.BREADTH, new PageChanged(target, currentPage - 1));
}
});
add(new AjaxLink<Void>("previousLink") {
@Override
public void onClick(AjaxRequestTarget target) {
long current = getTable().getCurrentPage();
if (current == 0) {
return;
}
current--;
if (current < 0) {
current = 0;
}
send(getTable(), Broadcast.BREADTH, new PageChanged(target, (int) current));
}
});
add(new AjaxLink<Void>("nextLink") {
@Override
public void onClick(AjaxRequestTarget target) {
long current = getTable().getCurrentPage();
long totals = getTable().getPageCount();
if (current == totals) {
return;
}
current++;
if (current >= totals) {
current = totals - 1;
}
send(getTable(), Broadcast.BREADTH, new PageChanged(target, (int) current));
}
});
add(new TextField<Integer>("pageInput", new PropertyModel<Integer>(this, "currentPage")));
AjaxButton btn = new AjaxButton("submit", this) {
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
if (currentPage == getTable().getCurrentPage() + 1) {
return;
}
long totals = getTable().getPageCount();
currentPage = Math.min(currentPage, (int) totals);
currentPage = Math.max(currentPage, 0);
send(getTable(), Broadcast.BREADTH, new PageChanged(target, currentPage - 1));
}
@Override
protected void onError(AjaxRequestTarget target, Form<?> form) {
target.add(form);
}
};
add(btn);
setDefaultButton(btn);
add(new Label("navlabel", new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
long totals = getTable().getRowCount();
long items = getTable().getItemsPerPage();
long start = (currentPage - 1) * items + 1;
long end = start + items - 1;
end = Math.min(end, totals);
return start + " - " + end + " of " + totals;
}
}));
}
@Override
public void onEvent(IEvent<?> event) {
if (event.getPayload() instanceof PageChanged) {
PageChanged e = (PageChanged) event.getPayload();
currentPage = e.getPage() + 1;
rowsPerPage = (int) getTable().getItemsPerPage();
e.getTarget().add(this);
}
}
}
}

View File

@ -0,0 +1,16 @@
package com.pmease.gitop.web.common.component.dropzone;
import org.apache.wicket.Component;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
@SuppressWarnings("serial")
public class DropZoneBehavior extends Behavior {
@Override
public void renderHead(Component component, IHeaderResponse response) {
super.renderHead(component, response);
response.render(JavaScriptHeaderItem.forReference(DropZoneResourceReference.get()));
}
}

View File

@ -0,0 +1,19 @@
package com.pmease.gitop.web.common.component.dropzone;
import org.apache.wicket.request.resource.JavaScriptResourceReference;
public class DropZoneResourceReference extends JavaScriptResourceReference {
private static final long serialVersionUID = 1L;
public DropZoneResourceReference() {
super(DropZoneResourceReference.class, "dropzone.js");
}
private static final DropZoneResourceReference instance =
new DropZoneResourceReference();
public static DropZoneResourceReference get() {
return instance;
}
}

View File

@ -4,18 +4,24 @@ package com.pmease.gitop.web.model;
import org.apache.wicket.model.LoadableDetachableModel;
import com.pmease.commons.hibernate.AbstractEntity;
import com.pmease.commons.hibernate.dao.GenericDao;
import com.pmease.commons.hibernate.dao.GeneralDao;
import com.pmease.commons.loader.AppLoader;
public abstract class EntityModel<T extends AbstractEntity> extends LoadableDetachableModel<T> {
public class EntityModel<T extends AbstractEntity> extends LoadableDetachableModel<T> {
private static final long serialVersionUID = 1L;
protected T entity;
private final Class<T> entityClass;
abstract protected GenericDao<T> getDao();
protected GeneralDao getDao() {
return AppLoader.getInstance(GeneralDao.class);
}
public EntityModel(T entity) {
@SuppressWarnings("unchecked")
public EntityModel(T entity) {
this.entity = entity;
this.entityClass = (Class<T>) entity.getClass();
}
@Override
@ -23,7 +29,7 @@ public abstract class EntityModel<T extends AbstractEntity> extends LoadableDeta
if (entity.isNew()) {
return entity;
} else {
return getDao().get(entity.getId());
return getDao().get(entityClass, entity.getId());
}
}

View File

@ -0,0 +1,13 @@
package com.pmease.gitop.web.model;
import com.pmease.gitop.core.model.Project;
/** Shortcut for {@link EntityModel}<Project> */
public class ProjectModel extends EntityModel<Project> {
private static final long serialVersionUID = 1L;
public ProjectModel(Project entity) {
super(entity);
}
}

View File

@ -1,10 +1,8 @@
package com.pmease.gitop.web.model;
import com.pmease.commons.hibernate.dao.GenericDao;
import com.pmease.commons.loader.AppLoader;
import com.pmease.gitop.core.manager.UserManager;
import com.pmease.gitop.core.model.User;
/** shortcut to {@link EntityModel}<User> */
public class UserModel extends EntityModel<User> {
private static final long serialVersionUID = 1L;
@ -13,9 +11,4 @@ public class UserModel extends EntityModel<User> {
super(entity);
}
@Override
protected GenericDao<User> getDao() {
return AppLoader.getInstance(UserManager.class);
}
}

View File

@ -0,0 +1,21 @@
<html xmlns:wicket>
<wicket:extend>
<section>
<div class="head">
<h2>Account Permissions</h2>
</div>
<div class="body">
<h4>Anonymous Users</h4>
<p><a>Anonymous users can browse and pull any repositories under this account </a></p>
<hr/>
<h4>Logged-in Users</h4>
<p class="text-muted">Logged-in users can access any repositories under this account with permission:</p>
<hr/>
<h4>Teams</h4>
<p class="text-muted"></p>
</div>
</section>
</wicket:extend>
</html>

View File

@ -1,27 +1,11 @@
<html xmlns:wicket>
<wicket:extend>
<div class="container">
<h2>Messenger Test</h2>
<div class="btn-group">
<a class="btn btn-info" wicket:id="ajaxinfo">ajax info</a>
<a class="btn btn-danger" wicket:id="ajaxerror">ajax error</a>
<a class="btn btn-success" wicket:id="ajaxsuccess">ajax success</a>
</div>
<p></p>
<h3>Flat UI Form</h3>
<form class="custom-form" wicket:id="form">
<div wicket:id="feedback" class="form-feedback"></div>
<div wicket:id="check"></div>
<wicket:container wicket:id="group">
<wicket:container wicket:id="radio">
<wicket:container wicket:id="element"></wicket:container>
</wicket:container>
</wicket:container>
<button class="btn btn-primary" wicket:id="btn">Submit</button>
</form>
<form class="dropzone" enctype="multipart/form-data" action="/rest/file/upload">
<div class="fallback">
<input name="file" type="file" multiple />
</div>
</form>
</div>
</wicket:extend>
</html>

View File

@ -1,21 +1,7 @@
package com.pmease.gitop.web.page.home;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.RadioGroup;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import com.google.common.collect.ImmutableList;
import com.pmease.gitop.web.common.component.messenger.Messenger;
import com.pmease.gitop.web.common.component.vex.AjaxConfirmButton;
import com.pmease.gitop.web.common.component.dropzone.DropZoneBehavior;
import com.pmease.gitop.web.common.component.vex.VexLinkBehavior.VexIcon;
import com.pmease.gitop.web.common.form.FeedbackPanel;
import com.pmease.gitop.web.common.form.flatcheckbox.FlatCheckBoxElement;
import com.pmease.gitop.web.common.form.flatradio.FlatRadioElement;
import com.pmease.gitop.web.page.AbstractLayoutPage;
public class HomePage extends AbstractLayoutPage {
@ -27,67 +13,11 @@ public class HomePage extends AbstractLayoutPage {
return "Gitop - Home";
}
@SuppressWarnings("serial")
@Override
protected void onInitialize() {
super.onInitialize();
// add(new BookmarkablePageLink<>("accountLink", AccountHomePage.class, AccountHomePage.paramsOf(Gitop.getInstance(UserManager.class).getRootUser())));
// add(new BookmarkablePageLink<>("projectLink", ProjectHomePage.class, ProjectHomePage.paramsOf(Gitop.getInstance(ProjectManager.class).load(1L))));
add(new AjaxLink<Void>("ajaxinfo") {
@Override
public void onClick(AjaxRequestTarget target) {
Messenger.info("ajax info clicked").execute(target);;
}
});
add(new AjaxLink<Void>("ajaxerror") {
@Override
public void onClick(AjaxRequestTarget target) {
Messenger.error("ajax error clicked").execute(target);;
}
});
add(new AjaxLink<Void>("ajaxsuccess") {
@Override
public void onClick(AjaxRequestTarget target) {
Messenger.success("ajax success clicked!").execute(target);;
}
});
Form<?> form = new Form<Void>("form");
add(form);
form.add(new FeedbackPanel("feedback"));
form.add(new FlatCheckBoxElement("check", new PropertyModel<Boolean>(this, "displayed"),
Model.of("Displayed screen")));
form.add(new AjaxConfirmButton("btn", form, Model.of("Are you want to save this form?")) {
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
if (displayed) {
form.info("yes");
target.add(form);
return;
}
System.out.println("Here is " + vexIcon);
target.add(form);
}
});
RadioGroup<VexIcon> group = new RadioGroup<VexIcon>("group", new PropertyModel<VexIcon>(this, "vexIcon"));
form.add(group);
group.add(new ListView<VexIcon>("radio", ImmutableList.<VexIcon>copyOf(VexIcon.values())) {
@Override
protected void populateItem(ListItem<VexIcon> item) {
// item.add(new Radio<VexIcon>("element", item.getModel()));
item.add(new FlatRadioElement<VexIcon>("element", item.getModel(), item.getDefaultModelObjectAsString()));
}
});
add(new DropZoneBehavior());
}
VexIcon vexIcon = VexIcon.INFO;

View File

@ -69,7 +69,9 @@ public class ProjectHomePage extends AbstractLayoutPage {
@Override
public void detachModels() {
projectModel.detach();
if (projectModel != null)
projectModel.detach();
super.detachModels();
}

View File

@ -33,6 +33,12 @@ public class TestResource {
@Inject ObjectMapper objectMapper;
@GET
@Path("test")
public String test() {
return "Hello, Jersey";
}
@GET
public String getResult() throws JsonProcessingException {
Result result = new Result();