http://git-wip-us.apache.org/repos/asf/isis/blob/a4ec0b72/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.java ---------------------------------------------------------------------- diff --git a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.java b/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.java deleted file mode 100644 index 7c528ac..0000000 --- a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.java +++ /dev/null @@ -1,140 +0,0 @@ -#set( $symbol_pound = '#' ) -#set( $symbol_dollar = '$' ) -#set( $symbol_escape = '\' ) -/* - * 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. - */ -package app; - -import app.ToDoItemAnalysis.DateRange; -import dom.todo.ToDoItem; -import dom.todo.ToDoItems; - -import java.util.List; -import com.google.common.base.Objects; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import org.joda.time.DateTime; -import org.apache.isis.applib.annotation.BookmarkPolicy; -import org.apache.isis.applib.annotation.CollectionLayout; -import org.apache.isis.applib.annotation.DomainObject; -import org.apache.isis.applib.annotation.DomainObjectLayout; -import org.apache.isis.applib.annotation.Nature; -import org.apache.isis.applib.annotation.RenderType; -import org.apache.isis.applib.annotation.Title; -import org.apache.isis.applib.services.clock.ClockService; -import org.apache.isis.applib.util.ObjectContracts; - -@DomainObjectLayout( - named="By Date Range", - bookmarking = BookmarkPolicy.AS_ROOT -) -@DomainObject( - nature = Nature.VIEW_MODEL -) -public class ToDoItemsByDateRangeViewModel - implements Comparable<ToDoItemsByDateRangeViewModel> { - - //region > constructors - public ToDoItemsByDateRangeViewModel() { - } - public ToDoItemsByDateRangeViewModel(final DateRange dateRange) { - setDateRange(dateRange); - } - //endregion - - //region > dateRange (property) - private DateRange dateRange; - - @Title - public DateRange getDateRange() { - return dateRange; - } - - public void setDateRange(final DateRange dateRange) { - this.dateRange = dateRange; - } - //endregion - - //region > count (derived property) - public int getCount() { - return getItemsNotYetComplete().size(); - } - //endregion - - //region > getItemsNotYetComplete (collection) - /** - * All those items {@link ToDoItems${symbol_pound}notYetComplete() not yet complete}, for this {@link ${symbol_pound}getDateRange() date range}. - */ - @CollectionLayout( - render = RenderType.EAGERLY - ) - public List<ToDoItem> getItemsNotYetComplete() { - final List<ToDoItem> notYetComplete = toDoItems.notYetCompleteNoUi(); - return Lists.newArrayList(Iterables.filter(notYetComplete, thoseInDateRange())); - } - - private Predicate<ToDoItem> thoseInDateRange() { - return new Predicate<ToDoItem>() { - @Override - public boolean apply(final ToDoItem t) { - return Objects.equal(dateRangeFor(t), getDateRange()); - } - }; - } - - private DateRange dateRangeFor(final ToDoItem t) { - if(t.getDueBy() == null) { - return DateRange.Unknown; - } - final DateTime dueBy = t.getDueBy().toDateTimeAtStartOfDay(); - final DateTime today = clockService.now().toDateTimeAtStartOfDay(); - - if(dueBy.isBefore(today)) { - return DateRange.OverDue; - } - if(dueBy.isBefore(today.plusDays(1))) { - return DateRange.Today; - } - if(dueBy.isBefore(today.plusDays(2))) { - return DateRange.Tomorrow; - } - if(dueBy.isBefore(today.plusDays(7))) { - return DateRange.ThisWeek; - } - return DateRange.Later; - } - //endregion - - //region > compareTo - @Override - public int compareTo(final ToDoItemsByDateRangeViewModel other) { - return ObjectContracts.compare(this, other, "dateRange"); - } - //endregion - - //region > injected services - @javax.inject.Inject - private ToDoItems toDoItems; - - @javax.inject.Inject - private ClockService clockService; - //endregion - -}
http://git-wip-us.apache.org/repos/asf/isis/blob/a4ec0b72/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.layout.json ---------------------------------------------------------------------- diff --git a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.layout.json b/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.layout.json deleted file mode 100644 index 648e146..0000000 --- a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.layout.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "columns": [ - { - "span": 4, - "memberGroups": { - "General": { - "members": { - "dateRange": {}, - "count": {} - } - } - } - }, - { - "span": 0, - "memberGroups": {} - }, - { - "span": 0, - "memberGroups": {} - }, - { - "span": 8, - "collections": { - "itemsNotYetComplete": {} - } - } - ], - "actions": { - "downloadLayout": {}, - "refreshLayout": {} - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/isis/blob/a4ec0b72/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.png ---------------------------------------------------------------------- diff --git a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.png b/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.png deleted file mode 100644 index 034a1f9..0000000 Binary files a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.png and /dev/null differ http://git-wip-us.apache.org/repos/asf/isis/blob/a4ec0b72/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/Categorized.java ---------------------------------------------------------------------- diff --git a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/Categorized.java b/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/Categorized.java deleted file mode 100644 index 9bb6bad..0000000 --- a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/Categorized.java +++ /dev/null @@ -1,35 +0,0 @@ -#set( $symbol_pound = '#' ) -#set( $symbol_dollar = '$' ) -#set( $symbol_escape = '\' ) -/* - * 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. - */ -package dom.todo; - -/** - * Enables {@link dom.todo.ToDoItemContributions${symbol_pound}updateCategory(dom.todo.Categorized, dom.todo.ToDoItem.Category, dom.todo.ToDoItem.Subcategory)} to be contributed to - * both the {@link dom.todo.ToDoItem} (entity) and also the {@link app.ToDoItemWizard} (wizard). - */ -public interface Categorized { - - ToDoItem.Category getCategory(); - void setCategory(ToDoItem.Category category); - - ToDoItem.Subcategory getSubcategory(); - void setSubcategory(ToDoItem.Subcategory subcategory); -} http://git-wip-us.apache.org/repos/asf/isis/blob/a4ec0b72/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem-done.png ---------------------------------------------------------------------- diff --git a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem-done.png b/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem-done.png deleted file mode 100644 index b0fc6e8..0000000 Binary files a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem-done.png and /dev/null differ http://git-wip-us.apache.org/repos/asf/isis/blob/a4ec0b72/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem-todo.png ---------------------------------------------------------------------- diff --git a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem-todo.png b/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem-todo.png deleted file mode 100644 index 99a9fed..0000000 Binary files a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem-todo.png and /dev/null differ http://git-wip-us.apache.org/repos/asf/isis/blob/a4ec0b72/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.java ---------------------------------------------------------------------- diff --git a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.java b/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.java deleted file mode 100644 index cadc117..0000000 --- a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.java +++ /dev/null @@ -1,982 +0,0 @@ -#set( $symbol_pound = '#' ) -#set( $symbol_dollar = '$' ) -#set( $symbol_escape = '\' ) -/* - * 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. - */ -package dom.todo; - -import java.math.BigDecimal; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; -import javax.jdo.JDOHelper; -import javax.jdo.annotations.IdentityType; -import javax.jdo.annotations.VersionStrategy; -import com.google.common.base.Objects; -import com.google.common.base.Predicate; -import com.google.common.collect.Ordering; -import org.joda.time.LocalDate; -import org.apache.isis.applib.DomainObjectContainer; -import org.apache.isis.applib.Identifier; -import org.apache.isis.applib.NonRecoverableException; -import org.apache.isis.applib.RecoverableException; -import org.apache.isis.applib.annotation.Action; -import org.apache.isis.applib.annotation.BookmarkPolicy; -import org.apache.isis.applib.annotation.Collection; -import org.apache.isis.applib.annotation.CollectionLayout; -import org.apache.isis.applib.annotation.DomainObject; -import org.apache.isis.applib.annotation.DomainObjectLayout; -import org.apache.isis.applib.annotation.Editing; -import org.apache.isis.applib.annotation.RestrictTo; -import org.apache.isis.applib.annotation.InvokeOn; -import org.apache.isis.applib.annotation.InvokedOn; -import org.apache.isis.applib.annotation.Optionality; -import org.apache.isis.applib.annotation.Parameter; -import org.apache.isis.applib.annotation.ParameterLayout; -import org.apache.isis.applib.annotation.Programmatic; -import org.apache.isis.applib.annotation.Property; -import org.apache.isis.applib.annotation.SemanticsOf; -import org.apache.isis.applib.annotation.Where; -import org.apache.isis.applib.security.UserMemento; -import org.apache.isis.applib.services.actinvoc.ActionInvocationContext; -import org.apache.isis.applib.services.eventbus.ActionDomainEvent; -import org.apache.isis.applib.services.eventbus.EventBusService; -import org.apache.isis.applib.services.scratchpad.Scratchpad; -import org.apache.isis.applib.services.wrapper.HiddenException; -import org.apache.isis.applib.services.wrapper.WrapperFactory; -import org.apache.isis.applib.util.ObjectContracts; -import org.apache.isis.applib.util.TitleBuffer; -import org.apache.isis.applib.value.Blob; -import org.apache.isis.applib.value.Clob; - [email protected](identityType=IdentityType.DATASTORE) [email protected]( - strategy=javax.jdo.annotations.IdGeneratorStrategy.IDENTITY, - column="id") [email protected]( - strategy=VersionStrategy.VERSION_NUMBER, - column="version") [email protected]({ - @javax.jdo.annotations.Unique( - name="ToDoItem_description_must_be_unique", - members={"ownedBy","description"}) -}) [email protected]( { - @javax.jdo.annotations.Query( - name = "findByOwnedBy", language = "JDOQL", - value = "SELECT " - + "FROM dom.todo.ToDoItem " - + "WHERE ownedBy == :ownedBy"), - @javax.jdo.annotations.Query( - name = "findByOwnedByAndCompleteIsFalse", language = "JDOQL", - value = "SELECT " - + "FROM dom.todo.ToDoItem " - + "WHERE ownedBy == :ownedBy " - + " && complete == false"), - @javax.jdo.annotations.Query( - name = "findByOwnedByAndCompleteIsTrue", language = "JDOQL", - value = "SELECT " - + "FROM dom.todo.ToDoItem " - + "WHERE ownedBy == :ownedBy " - + "&& complete == true"), - @javax.jdo.annotations.Query( - name = "findByOwnedByAndCategory", language = "JDOQL", - value = "SELECT " - + "FROM dom.todo.ToDoItem " - + "WHERE ownedBy == :ownedBy " - + "&& category == :category"), - @javax.jdo.annotations.Query( - name = "findByOwnedByAndDescriptionContains", language = "JDOQL", - value = "SELECT " - + "FROM dom.todo.ToDoItem " - + "WHERE ownedBy == :ownedBy && " - + "description.indexOf(:description) >= 0") -}) -@DomainObject( - autoCompleteRepository = ToDoItems.class, // for drop-downs, unless autoCompleteNXxx() is present - autoCompleteAction = "autoComplete", - // bounded = true, // for drop-downs if only a small number of instances only (overrides autoComplete) - objectType = "TODO" -) -@DomainObjectLayout( - bookmarking = BookmarkPolicy.AS_ROOT -) -public class ToDoItem implements Categorized, Comparable<ToDoItem> { - - //region > LOG - /** - * It isn't common for entities to log, but they can if required. - * Isis uses slf4j API internally (with log4j as implementation), and is the recommended API to use. - */ - private final static org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(ToDoItem.class); - //endregion - - // region > title, icon - public String title() { - final TitleBuffer buf = new TitleBuffer(); - buf.append(getDescription()); - if (isComplete()) { - buf.append("- Completed!"); - } else { - try { - final LocalDate dueBy = wrapperFactory.wrap(this).getDueBy(); - if (dueBy != null) { - buf.append(" due by", dueBy); - } - } catch(final HiddenException ignored) { - } - } - return buf.toString(); - } - - public String iconName() { - return !isComplete() ? "todo" : "done"; - } - - public String cssClass() { return iconName(); } - - //endregion - - //region > description (property) - private String description; - - @javax.jdo.annotations.Column(allowsNull="false", length=100) - @Property( - regexPattern = "${symbol_escape}${symbol_escape}w[@&:${symbol_escape}${symbol_escape}-${symbol_escape}${symbol_escape},${symbol_escape}${symbol_escape}.${symbol_escape}${symbol_escape}+ ${symbol_escape}${symbol_escape}w]*" - ) - public String getDescription() { - return description; - } - - public void setDescription(final String description) { - this.description = description; - } - public void modifyDescription(final String description) { - setDescription(description); - } - public void clearDescription() { - setDescription(null); - } - //endregion - - //region > dueBy (property) - @javax.jdo.annotations.Persistent(defaultFetchGroup="true") - private LocalDate dueBy; - - @javax.jdo.annotations.Column(allowsNull="true") - public LocalDate getDueBy() { - return dueBy; - } - - /** - * Demonstrates how to perform security checks within the domain code. - * - * <p> - * Generally speaking this approach is not recommended; such checks should - * wherever possible be externalized in the security subsystem. - * </p> - */ - public boolean hideDueBy() { - final UserMemento user = container.getUser(); - return user.hasRole("realm1:noDueBy_role"); - } - - public void setDueBy(final LocalDate dueBy) { - this.dueBy = dueBy; - } - public void clearDueBy() { - setDueBy(null); - } - // proposed new value is validated before setting - public String validateDueBy(final LocalDate dueBy) { - if (dueBy == null) { - return null; - } - return toDoItems.validateDueBy(dueBy); - } - //endregion - - //region > category and subcategory (property) - - public static enum Category { - Professional { - @Override - public List<Subcategory> subcategories() { - return Arrays.asList(null, Subcategory.OpenSource, Subcategory.Consulting, Subcategory.Education, Subcategory.Marketing); - } - }, Domestic { - @Override - public List<Subcategory> subcategories() { - return Arrays.asList(null, Subcategory.Shopping, Subcategory.Housework, Subcategory.Garden, Subcategory.Chores); - } - }, Other { - @Override - public List<Subcategory> subcategories() { - return Arrays.asList(null, Subcategory.Other); - } - }; - - public abstract List<Subcategory> subcategories(); - } - - public static enum Subcategory { - // professional - OpenSource, Consulting, Education, Marketing, - // domestic - Shopping, Housework, Garden, Chores, - // other - Other; - - public static List<Subcategory> listFor(final Category category) { - return category != null? category.subcategories(): Collections.<Subcategory>emptyList(); - } - - static String validate(final Category category, final Subcategory subcategory) { - if(category == null) { - return "Enter category first"; - } - return !category.subcategories().contains(subcategory) - ? "Invalid subcategory for category '" + category + "'" - : null; - } - - public static Predicate<Subcategory> thoseFor(final Category category) { - return new Predicate<Subcategory>() { - - @Override - public boolean apply(final Subcategory subcategory) { - return category.subcategories().contains(subcategory); - } - }; - } - } - - // ////////////////////////////////////// - - private Category category; - - @javax.jdo.annotations.Column(allowsNull="false") - @Property( - editing = Editing.DISABLED, - editingDisabledReason = "Use action to update both category and subcategory" - ) - public Category getCategory() { - return category; - } - - public void setCategory(final Category category) { - this.category = category; - } - - // ////////////////////////////////////// - - private Subcategory subcategory; - - @javax.jdo.annotations.Column(allowsNull="true") - @Property( - editing = Editing.DISABLED, - editingDisabledReason = "Use action to update both category and subcategory" - ) - public Subcategory getSubcategory() { - return subcategory; - } - public void setSubcategory(final Subcategory subcategory) { - this.subcategory = subcategory; - } - //endregion - - //region > ownedBy (property) - - private String ownedBy; - - @javax.jdo.annotations.Column(allowsNull="false") - public String getOwnedBy() { - return ownedBy; - } - - public void setOwnedBy(final String ownedBy) { - this.ownedBy = ownedBy; - } - //endregion - - //region > complete (property), completed (action), notYetCompleted (action) - - private boolean complete; - - @Property( - editing = Editing.DISABLED - ) - public boolean isComplete() { - return complete; - } - - public void setComplete(final boolean complete) { - this.complete = complete; - } - - @Action( - domainEvent =CompletedEvent.class, - invokeOn = InvokeOn.OBJECT_AND_COLLECTION - ) - public ToDoItem completed() { - setComplete(true); - - // - // remainder of method just demonstrates the use of the Bulk.InteractionContext service - // - @SuppressWarnings("unused") - final List<Object> allObjects = actionInvocationContext.getDomainObjects(); - - LOG.debug("completed: " - + actionInvocationContext.getIndex() + - " [" + actionInvocationContext.getSize() + "]" - + (actionInvocationContext.isFirst() ? " (first)" : "") - + (actionInvocationContext.isLast() ? " (last)" : "")); - - // if invoked as a regular action, return this object; - // otherwise (if invoked as bulk), return null (so go back to the list) - return actionInvocationContext.getInvokedOn() == InvokedOn.OBJECT? this: null; - } - // disable action dependent on state of object - public String disableCompleted() { - return isComplete() ? "Already completed" : null; - } - - @Action( - invokeOn = InvokeOn.OBJECT_AND_COLLECTION - ) - public ToDoItem notYetCompleted() { - setComplete(false); - - // if invoked as a regular action, return this object; - // otherwise (if invoked as bulk), return null (so go back to the list) - return actionInvocationContext.getInvokedOn() == InvokedOn.OBJECT ? this: null; - } - // disable action dependent on state of object - public String disableNotYetCompleted() { - return !complete ? "Not yet completed" : null; - } - //endregion - - //region > completeSlowly (property) - // //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - @Action( - hidden = Where.EVERYWHERE - ) - public void completeSlowly(final int millis) { - try { - Thread.sleep(millis); - } catch (final InterruptedException ignored) { - } - setComplete(true); - } - //endregion - - //region > cost (property), updateCost (action) - private BigDecimal cost; - - @javax.jdo.annotations.Column(allowsNull="true", scale=2) - @javax.validation.constraints.Digits(integer=10, fraction=2) - @Property( - editing = Editing.DISABLED, - editingDisabledReason = "Update using action" - ) - public BigDecimal getCost() { - return cost; - } - - public void setCost(final BigDecimal cost) { - this.cost = cost!=null?cost.setScale(2, BigDecimal.ROUND_HALF_EVEN):null; - } - - @Action( - semantics = SemanticsOf.IDEMPOTENT - ) - public ToDoItem updateCost( - @Parameter(optional = Optionality.TRUE) - @ParameterLayout(named = "New cost") - @javax.validation.constraints.Digits(integer=10, fraction=2) - final BigDecimal cost) { - LOG.debug("%s: cost updated: %s -> %s", container.titleOf(this), getCost(), cost); - - // just to simulate a long-running action - try { - Thread.sleep(3000); - } catch (final InterruptedException ignored) { - } - - setCost(cost); - return this; - } - - // provide a default value for argument ${symbol_pound}0 - public BigDecimal default0UpdateCost() { - return getCost(); - } - - // validate action arguments - public String validateUpdateCost(final BigDecimal proposedCost) { - if(proposedCost == null) { return null; } - return proposedCost.compareTo(BigDecimal.ZERO) < 0? "Cost must be positive": null; - } - //endregion - - //region > notes (property) - private String notes; - - @javax.jdo.annotations.Column(allowsNull="true", length=400) - public String getNotes() { - return notes; - } - - public void setNotes(final String notes) { - this.notes = notes; - } - //endregion - - //region > attachment (property) - private Blob attachment; - @javax.jdo.annotations.Persistent(defaultFetchGroup="false", columns = { - @javax.jdo.annotations.Column(name = "attachment_name"), - @javax.jdo.annotations.Column(name = "attachment_mimetype"), - @javax.jdo.annotations.Column(name = "attachment_bytes", jdbcType = "BLOB", sqlType = "BLOB") - }) - @Property( - optional = Optionality.TRUE - ) - public Blob getAttachment() { - return attachment; - } - - public void setAttachment(final Blob attachment) { - this.attachment = attachment; - } - //endregion - - //region > doc (property) - private Clob doc; - @javax.jdo.annotations.Persistent(defaultFetchGroup="false", columns = { - @javax.jdo.annotations.Column(name = "doc_name"), - @javax.jdo.annotations.Column(name = "doc_mimetype"), - @javax.jdo.annotations.Column(name = "doc_chars", jdbcType = "CLOB", sqlType = "CLOB") - }) - @Property( - optional = Optionality.TRUE - ) - public Clob getDoc() { - return doc; - } - - public void setDoc(final Clob doc) { - this.doc = doc; - } - //endregion - - //region > version (derived property) - public Long getVersionSequence() { - if(!(this instanceof javax.jdo.spi.PersistenceCapable)) { - return null; - } - return (Long) JDOHelper.getVersion((javax.jdo.spi.PersistenceCapable) this); - } - // hide property (imperatively, based on state of object) - public boolean hideVersionSequence() { - return !(this instanceof javax.jdo.spi.PersistenceCapable); - } - //endregion - - //region > dependencies (property), add (action), remove (action) - - // overrides the natural ordering - public static class DependenciesComparator implements Comparator<ToDoItem> { - @Override - public int compare(final ToDoItem p, final ToDoItem q) { - final Ordering<ToDoItem> byDescription = new Ordering<ToDoItem>() { - public int compare(final ToDoItem p, final ToDoItem q) { - return Ordering.natural().nullsFirst().compare(p.getDescription(), q.getDescription()); - } - }; - return byDescription - .compound(Ordering.<ToDoItem>natural()) - .compare(p, q); - } - } - - @javax.jdo.annotations.Persistent(table="ToDoItemDependencies") - @javax.jdo.annotations.Join(column="dependingId") - @javax.jdo.annotations.Element(column="dependentId") - - private Set<ToDoItem> dependencies = new TreeSet<>(); - //private SortedSet<ToDoItem> dependencies = new TreeSet<>(); // not compatible with neo4j (as of DN v3.2.3) - - @Collection() - @CollectionLayout(/*sortedBy = DependenciesComparator.class*/) // not compatible with neo4j (as of DN v3.2.3) - public Set<ToDoItem> getDependencies() { - return dependencies; - } - - public void setDependencies(final Set<ToDoItem> dependencies) { - this.dependencies = dependencies; - } - - public void addToDependencies(final ToDoItem toDoItem) { - getDependencies().add(toDoItem); - } - public void removeFromDependencies(final ToDoItem toDoItem) { - getDependencies().remove(toDoItem); - } - - public ToDoItem add( - @ParameterLayout(typicalLength = 20) - final ToDoItem toDoItem) { - // By wrapping the call, Isis will detect that the collection is modified - // and it will automatically send CollectionInteractionEvents to the Event Bus. - // ToDoItemSubscriptions is a demo subscriber to this event - wrapperFactory.wrapSkipRules(this).addToDependencies(toDoItem); - return this; - } - public List<ToDoItem> autoComplete0Add( - @Parameter(minLength = 2) - final String search) { - final List<ToDoItem> list = toDoItems.autoComplete(search); - list.removeAll(getDependencies()); - list.remove(this); - return list; - } - - public String disableAdd(final ToDoItem toDoItem) { - if(isComplete()) { - return "Cannot add dependencies for items that are complete"; - } - return null; - } - // validate the provided argument prior to invoking action - public String validateAdd(final ToDoItem toDoItem) { - if(getDependencies().contains(toDoItem)) { - return "Already a dependency"; - } - if(toDoItem == this) { - return "Can't set up a dependency to self"; - } - return null; - } - - public ToDoItem remove( - @ParameterLayout(typicalLength = 20) - final ToDoItem toDoItem) { - // By wrapping the call, Isis will detect that the collection is modified - // and it will automatically send a CollectionInteractionEvent to the Event Bus. - // ToDoItemSubscriptions is a demo subscriber to this event - wrapperFactory.wrapSkipRules(this).removeFromDependencies(toDoItem); - return this; - } - // disable action dependent on state of object - public String disableRemove(final ToDoItem toDoItem) { - if(isComplete()) { - return "Cannot remove dependencies for items that are complete"; - } - return getDependencies().isEmpty()? "No dependencies to remove": null; - } - // validate the provided argument prior to invoking action - public String validateRemove(final ToDoItem toDoItem) { - if(!getDependencies().contains(toDoItem)) { - return "Not a dependency"; - } - return null; - } - // provide a drop-down - public java.util.Collection<ToDoItem> choices0Remove() { - return getDependencies(); - } - //endregion - - //region > clone (action) - - // the name of the action in the UI - // nb: method is not called "clone()" is inherited by java.lang.Object and - // (a) has different semantics and (b) is in any case automatically ignored - // by the framework - public ToDoItem duplicate( - @Parameter(regexPattern = "${symbol_escape}${symbol_escape}w[@&:${symbol_escape}${symbol_escape}-${symbol_escape}${symbol_escape},${symbol_escape}${symbol_escape}.${symbol_escape}${symbol_escape}+ ${symbol_escape}${symbol_escape}w]*" ) - @ParameterLayout(named="Description") - final String description, - @ParameterLayout(named="Category") - final Category category, - @ParameterLayout(named="Subcategory") - final Subcategory subcategory, - @Parameter(optional = Optionality.TRUE) - @ParameterLayout(named="Due by") - final LocalDate dueBy, - @Parameter(optional = Optionality.TRUE) - @ParameterLayout(named="Cost") - final BigDecimal cost) { - return toDoItems.newToDo(description, category, subcategory, dueBy, cost); - } - public String default0Duplicate() { - return getDescription() + " - Copy"; - } - public Category default1Duplicate() { - return getCategory(); - } - public Subcategory default2Duplicate() { - return getSubcategory(); - } - public LocalDate default3Duplicate() { - return getDueBy(); - } - public List<Subcategory> choices2Duplicate( - final String description, final Category category) { - return toDoItems.choices2NewToDo(description, category); - } - public String validateDuplicate( - final String description, - final Category category, final Subcategory subcategory, - final LocalDate dueBy, final BigDecimal cost) { - return toDoItems.validateNewToDo(description, category, subcategory, dueBy, cost); - } - //endregion - - //region > delete (action) - @Action( - domainEvent =DeletedEvent.class, - invokeOn = InvokeOn.OBJECT_AND_COLLECTION - ) - public List<ToDoItem> delete() { - - container.removeIfNotAlready(this); - - container.informUser("Deleted " + container.titleOf(this)); - - // invalid to return 'this' (cannot render a deleted object) - return toDoItems.notYetComplete(); - } - //endregion - - //region > totalCost (property) - @Action( - semantics = SemanticsOf.SAFE, - invokeOn = InvokeOn.COLLECTION_ONLY - ) - public BigDecimal totalCost() { - BigDecimal total = (BigDecimal) scratchpad.get("runningTotal"); - if(getCost() != null) { - total = total != null ? total.add(getCost()) : getCost(); - scratchpad.put("runningTotal", total); - } - return total.setScale(2, BigDecimal.ROUND_HALF_EVEN); - } - //endregion - - //region > openSourceCodeOnGithub (action) - @Action( - semantics = SemanticsOf.SAFE, - restrictTo = RestrictTo.PROTOTYPING - ) - public URL openSourceCodeOnGithub() throws MalformedURLException { - return new URL("https://github.com/apache/isis/tree/master/example/application/${parentArtifactId}/dom/src/main/java/dom/todo/ToDoItem.java"); - } - //endregion - - //region > demoException (action) - - static enum DemoExceptionType { - RecoverableException, - RecoverableExceptionAutoEscalated, - NonRecoverableException; - } - - @Action( - semantics = SemanticsOf.SAFE, - restrictTo = RestrictTo.PROTOTYPING - ) - public void demoException( - @ParameterLayout(named="Type") - final DemoExceptionType type) { - switch(type) { - case NonRecoverableException: - throw new NonRecoverableException("Demo throwing " + type.name()); - case RecoverableException: - throw new RecoverableException("Demo throwing " + type.name()); - case RecoverableExceptionAutoEscalated: - try { - // this will trigger an exception (because category cannot be null), causing the xactn to be aborted - setCategory(null); - container.flush(); - } catch(Exception e) { - // it's a programming mistake to throw only a recoverable exception here, because of the xactn's state. - // the framework should instead auto-escalate this to a non-recoverable exception - throw new RecoverableException("Demo throwing " + type.name(), e); - } - } - } - //endregion - - //region > lifecycle callbacks - - public void created() { - LOG.debug("lifecycle callback: created: " + this.toString()); - } - public void loaded() { - LOG.debug("lifecycle callback: loaded: " + this.toString()); - } - public void persisting() { - LOG.debug("lifecycle callback: persisting: " + this.toString()); - } - public void persisted() { - LOG.debug("lifecycle callback: persisted: " + this.toString()); - } - public void updating() { - LOG.debug("lifecycle callback: updating: " + this.toString()); - } - public void updated() { - LOG.debug("lifecycle callback: updated: " + this.toString()); - } - public void removing() { - LOG.debug("lifecycle callback: removing: " + this.toString()); - } - public void removed() { - LOG.debug("lifecycle callback: removed: " + this.toString()); - } - //endregion - - //region > object-level validation - - /** - * Prevent user from viewing another user's data. - */ - public boolean hidden() { - // uncomment to enable. As things stand, the disabled() method below instead will make object "read-only". - //return !Objects.equal(getOwnedBy(), container.getUser().getName()); - return false; - } - - /** - * Prevent user from modifying any other user's data. - */ - public String disabled(final Identifier.Type identifierType){ - final UserMemento currentUser = container.getUser(); - final String currentUserName = currentUser.getName(); - if(Objects.equal(getOwnedBy(), currentUserName)) { return null; } - return "This object is owned by '" + getOwnedBy() + "' and cannot be modified by you"; - } - - /** - * In a real app, if this were actually a rule, then we'd expect that - * invoking the {@link ${symbol_pound}completed() done} action would clear the {@link ${symbol_pound}getDueBy() dueBy} - * property (rather than require the user to have to clear manually). - */ - public String validate() { - if(isComplete() && getDueBy() != null) { - return "Due by date must be set to null if item has been completed"; - } - return null; - } - - - //endregion - - - //region > programmatic helpers - @Programmatic // excluded from the framework's metamodel - public boolean isDue() { - if (getDueBy() == null) { - return false; - } - return !toDoItems.isMoreThanOneWeekInPast(getDueBy()); - } - //endregion - - //region > events - - public static abstract class AbstractActionDomainEvent extends ActionDomainEvent<ToDoItem> { - private static final long serialVersionUID = 1L; - private final String description; - public AbstractActionDomainEvent( - final String description, - final ToDoItem source, - final Identifier identifier, - final Object... arguments) { - super(source, identifier, arguments); - this.description = description; - } - public String getEventDescription() { - return description; - } - } - - public static class CompletedEvent extends AbstractActionDomainEvent { - private static final long serialVersionUID = 1L; - public CompletedEvent( - final ToDoItem source, - final Identifier identifier, - final Object... arguments) { - super("completed", source, identifier, arguments); - } - } - - public static class NoLongerCompletedEvent extends AbstractActionDomainEvent { - private static final long serialVersionUID = 1L; - public NoLongerCompletedEvent( - final ToDoItem source, - final Identifier identifier, - final Object... arguments) { - super("no longer completed", source, identifier, arguments); - } - } - - public static class DeletedEvent extends AbstractActionDomainEvent { - private static final long serialVersionUID = 1L; - public DeletedEvent( - final ToDoItem source, - final Identifier identifier, - final Object... arguments) { - super("deleted", source, identifier, arguments); - } - } - - //endregion - - //region > predicates - - public static class Predicates { - - public static Predicate<ToDoItem> thoseOwnedBy(final String currentUser) { - return new Predicate<ToDoItem>() { - @Override - public boolean apply(final ToDoItem toDoItem) { - return Objects.equal(toDoItem.getOwnedBy(), currentUser); - } - }; - } - - public static Predicate<ToDoItem> thoseCompleted( - final boolean completed) { - return new Predicate<ToDoItem>() { - @Override - public boolean apply(final ToDoItem t) { - return Objects.equal(t.isComplete(), completed); - } - }; - } - - public static Predicate<ToDoItem> thoseWithSimilarDescription(final String description) { - return new Predicate<ToDoItem>() { - @Override - public boolean apply(final ToDoItem t) { - return t.getDescription().contains(description); - } - }; - } - - @SuppressWarnings("unchecked") - public static Predicate<ToDoItem> thoseSimilarTo(final ToDoItem toDoItem) { - return com.google.common.base.Predicates.and( - thoseNot(toDoItem), - thoseOwnedBy(toDoItem.getOwnedBy()), - thoseCategorised(toDoItem.getCategory())); - } - - public static Predicate<ToDoItem> thoseNot(final ToDoItem toDoItem) { - return new Predicate<ToDoItem>() { - @Override - public boolean apply(final ToDoItem t) { - return t != toDoItem; - } - }; - } - - public static Predicate<ToDoItem> thoseCategorised(final Category category) { - return new Predicate<ToDoItem>() { - @Override - public boolean apply(final ToDoItem toDoItem) { - return Objects.equal(toDoItem.getCategory(), category); - } - }; - } - - public static Predicate<ToDoItem> thoseSubcategorised( - final Subcategory subcategory) { - return new Predicate<ToDoItem>() { - @Override - public boolean apply(final ToDoItem t) { - return Objects.equal(t.getSubcategory(), subcategory); - } - }; - } - - public static Predicate<ToDoItem> thoseCategorised( - final Category category, final Subcategory subcategory) { - return com.google.common.base.Predicates.and( - thoseCategorised(category), - thoseSubcategorised(subcategory)); - } - - } - - //endregion - - //region > toString, compareTo - @Override - public String toString() { - return ObjectContracts.toString(this, "description,complete,dueBy,ownedBy"); - } - - /** - * Required so can store in {@link SortedSet sorted set}s (eg {@link ${symbol_pound}getDependencies()}). - */ - @Override - public int compareTo(final ToDoItem other) { - return ObjectContracts.compare(this, other, "complete,dueBy,description"); - } - //endregion - - //region > injected services - @javax.inject.Inject - DomainObjectContainer container; - - @javax.inject.Inject - ToDoItems toDoItems; - - @javax.inject.Inject - Scratchpad scratchpad; - - /** - * public only so can be injected from integ tests - */ - @javax.inject.Inject - public ActionInvocationContext actionInvocationContext; - - /** - * public only so can be injected from integ tests - */ - @javax.inject.Inject - public EventBusService eventBusService; - - @javax.inject.Inject - WrapperFactory wrapperFactory; - - //endregion - -} http://git-wip-us.apache.org/repos/asf/isis/blob/a4ec0b72/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.layout.json ---------------------------------------------------------------------- diff --git a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.layout.json b/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.layout.json deleted file mode 100644 index cda5fdc..0000000 --- a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.layout.json +++ /dev/null @@ -1,222 +0,0 @@ -/** - * 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. - */ -{ - "columns": [ - { - "span": 6, - "memberGroups": { - "General": { - "members": { - "description": { - "propertyLayout": { - "cssClass": "x-key", - "labelPosition": "TOP" - } - }, - "category": { - "propertyLayout": { - "labelPosition": "TOP" - } - }, - "subcategory": { - "propertyLayout": { - "labelPosition": "NONE" - }, - "actions": { - "updateCategory": { - "actionLayout": { - "named": "Update" - } - }, - "analyseCategory": { - "actionLayout": { - "cssClass": "btn-default", - "cssClassFa": "fa fa-pie-chart" - } - } - } - }, - "ownedBy": { - "propertyLayout": { - "hidden": "EVERYWHERE" - } - }, - "complete": { - "propertyLayout": { - "named": "Whether this todo item has been <i>completed</i> or not.", - "namedEscaped": false, - "describedAs": "Whether this todo item has been completed, or not.", - "labelPosition": "LEFT" - }, - "actions": { - "completed": { - "actionLayout": { - "named": "Done", - "describedAs": "Update this todo item as complete", - "cssClass": "btn-success", - "cssClassFa": "fa fa-thumbs-up" - } - }, - "notYetCompleted": { - "actionLayout": { - "named": "Not done", - "describedAs": "Update this todo item as not yet complete", - "cssClass": "btn-info", - "cssClassFa": "fa fa-thumbs-down" - } - }, - "scheduleExplicitly": { - }, - "scheduleImplicitly": { - } - } - } - } - }, - "Misc": { - "members": { - "versionSequence": { - "propertyLayout": { - "named": "Version", - "hidden": "ALL_TABLES" - }, - "disabled": {} - } - } - } - } - }, - { - "span": 6, - "memberGroups": { - "Priority": { - "members": { - "relativePriority": { - "actions": { - "previous": { - "actionLayout": { - "cssClassFa": "fa fa-step-backward" - } - }, - "next": { - "actionLayout": { - "cssClassFa": "fa fa-step-forward", - "cssClassFaPosition": "right" - } - } - } - }, - "dueBy": { - "propertyLayout": { - "renderedAsDayBefore": "false" - } - } - } - }, - "Other": { - "members": { - "cost": { - "actions": { - "updateCost":{ - "actionLayout": { - "named": "Update", - "cssClassFa": "fa fa-dollar" - } - } - } - }, - "notes": { - "propertyLayout": { - "hidden": "ALL_TABLES", - "labelPosition": "TOP", - "multiLine": 5 - } - }, - "attachment": { - "propertyLayout": { - "hidden": "STANDALONE_TABLES" - } - }, - "doc": { - "propertyLayout": { - "hidden": "STANDALONE_TABLES" - } - } - } - } - } - }, - { - "span": 0 - }, - { - "span": 6, - "collections": { - "dependencies": { - "collectionLayout": { - "named": "Todo items that are <i>dependencies</i> of this item.", - "namedEscaped": false, - "describedAs": "Todo items that must be completed before this one", - "paged": 5, - "render": "EAGERLY" - }, - "disabled": {}, - "actions": { - "add":{ - "actionLayout": { - "cssClass": "btn-default", - "cssClassFa": "fa fa-plus-square" - } - }, - "remove": { - "actionLayout": { - "cssClass": "x-caution btn-default", - "cssClassFa": "fa fa-minus-square" - } - } - } - }, - "similarTo": { - "collectionLayout": { - "named": "Todo items that are <i>similar to</i> this one", - "namedEscaped": false, - "paged": 3, - "render": "LAZILY" - }, - "disabled": {} - } - } - } - ], - "actions": { - "totalCost": {}, - "delete": { - "actionLayout": { - "cssClass": "btn btn-danger", - "cssClassFa": "fa fa-trash fa-lg" - } - }, - "duplicate": { - "actionLayout": { - "named": "Clone", - "describedAs": "Create a new todo item from this one", - "cssClass": "btn-warn", - "cssClassFa": "fa fa-copy fa-lg" - } - } - } -} http://git-wip-us.apache.org/repos/asf/isis/blob/a4ec0b72/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.png ---------------------------------------------------------------------- diff --git a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.png b/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.png deleted file mode 100644 index 99a9fed..0000000 Binary files a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.png and /dev/null differ http://git-wip-us.apache.org/repos/asf/isis/blob/a4ec0b72/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.java ---------------------------------------------------------------------- diff --git a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.java b/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.java deleted file mode 100644 index 1d3b870..0000000 --- a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.java +++ /dev/null @@ -1,51 +0,0 @@ -#set( $symbol_pound = '#' ) -#set( $symbol_dollar = '$' ) -#set( $symbol_escape = '\' ) -/* - * 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. - */ -package dom.todo; - -import org.apache.isis.applib.annotation.PublishingChangeKind; -import org.apache.isis.applib.annotation.PublishingPayloadFactoryForObject; -import org.apache.isis.applib.services.publish.EventPayload; -import org.apache.isis.applib.services.publish.EventPayloadForObjectChanged; - -public class ToDoItemChangedPayloadFactory implements PublishingPayloadFactoryForObject { - - public static class ToDoItemPayload extends EventPayloadForObjectChanged<ToDoItem> { - - public ToDoItemPayload(ToDoItem changed) { - super(changed); - } - - /** - * Expose the item's {@link ToDoItem${symbol_pound}getDescription() description} more explicitly - * in the payload. - */ - public String getDescription() { - return getChanged().getDescription(); - } - } - - @Override - public EventPayload payloadFor(final Object changedObject, final PublishingChangeKind publishingChangeKind) { - return new ToDoItemPayload((ToDoItem) changedObject); - } - -} http://git-wip-us.apache.org/repos/asf/isis/blob/a4ec0b72/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemContributions.java ---------------------------------------------------------------------- diff --git a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemContributions.java b/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemContributions.java deleted file mode 100644 index c33097e..0000000 --- a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemContributions.java +++ /dev/null @@ -1,274 +0,0 @@ -#set( $symbol_pound = '#' ) -#set( $symbol_dollar = '$' ) -#set( $symbol_escape = '\' ) -/* - * 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. - */ -package dom.todo; - -import dom.todo.ToDoItem.Category; -import dom.todo.ToDoItem.Subcategory; - -import java.util.List; -import java.util.concurrent.Callable; -import com.google.common.base.Function; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.Ordering; -import org.joda.time.LocalDate; -import org.apache.isis.applib.AbstractFactoryAndRepository; -import org.apache.isis.applib.annotation.Action; -import org.apache.isis.applib.annotation.ActionLayout; -import org.apache.isis.applib.annotation.Contributed; -import org.apache.isis.applib.annotation.Disabled; -import org.apache.isis.applib.annotation.DomainService; -import org.apache.isis.applib.annotation.NatureOfService; -import org.apache.isis.applib.annotation.Optional; -import org.apache.isis.applib.annotation.ParameterLayout; -import org.apache.isis.applib.annotation.SemanticsOf; -import org.apache.isis.applib.annotation.Where; -import org.apache.isis.applib.query.QueryDefault; -import org.apache.isis.applib.services.queryresultscache.QueryResultsCache; -import org.apache.isis.applib.value.Clob; - -@DomainService(nature = NatureOfService.VIEW_CONTRIBUTIONS_ONLY) -public class ToDoItemContributions extends AbstractFactoryAndRepository { - - //region > priority (contributed property) - @Action( - semantics = SemanticsOf.SAFE, - hidden = Where.ALL_TABLES - ) - @ActionLayout( - describedAs = "The relative priority of this item compared to others not yet complete (using 'due by' date)", - contributed = Contributed.AS_ASSOCIATION - ) - @Disabled(reason="Relative priority, derived from due date") - public Integer relativePriority(final ToDoItem toDoItem) { - return queryResultsCache.execute(new Callable<Integer>(){ - @Override - public Integer call() throws Exception { - if(toDoItem.isComplete()) { - return null; - } - - // sort items, then locate this one - int i=1; - for (final ToDoItem each : sortedNotYetComplete()) { - if(each == toDoItem) { - return i; - } - i++; - } - return null; - }}, ToDoItemContributions.class, "relativePriority", toDoItem); - } - - private List<ToDoItem> sortedNotYetComplete() { - return ORDERING_DUE_BY - .compound(ORDERING_DESCRIPTION) - .sortedCopy(toDoItems.notYetComplete()); - } - - private static final Ordering<ToDoItem> ORDERING_DUE_BY = - Ordering.natural().nullsLast().onResultOf(new Function<ToDoItem, LocalDate>(){ - @Override - public LocalDate apply(final ToDoItem input) { - return input.getDueBy(); - } - }); - - private static final Ordering<ToDoItem> ORDERING_DESCRIPTION = - Ordering.natural().nullsLast().onResultOf(new Function<ToDoItem, String>(){ - @Override - public String apply(final ToDoItem input) { - return input.getDescription(); - } - }); - - - //endregion - - //region > next, previous (contributed actions) - @Action(semantics = SemanticsOf.SAFE) - @ActionLayout( - describedAs = "The next item not yet completed", - contributed = Contributed.AS_ACTION - ) - public ToDoItem next(final ToDoItem item) { - final Integer priority = relativePriority(item); - if(priority == null) { - return item; - } - int priorityOfNext = priority != null ? priority + 1 : 0; - return itemWithPriorityElse(priorityOfNext, item); - } - public String disableNext(final ToDoItem toDoItem) { - if (toDoItem.isComplete()) { - return "Completed"; - } - if(next(toDoItem) == null) { - return "No next item"; - } - return null; - } - - // ////////////////////////////////////// - - @ActionLayout( - describedAs = "The previous item not yet completed", - contributed = Contributed.AS_ACTION - ) - @Action(semantics = SemanticsOf.SAFE) - public ToDoItem previous(final ToDoItem item) { - final Integer priority = relativePriority(item); - if(priority == null) { - return item; - } - int priorityOfPrevious = priority != null? priority - 1 : 0; - return itemWithPriorityElse(priorityOfPrevious, item); - } - public String disablePrevious(final ToDoItem toDoItem) { - if (toDoItem.isComplete()) { - return "Completed"; - } - if(previous(toDoItem) == null) { - return "No previous item"; - } - return null; - } - - // ////////////////////////////////////// - - /** - * @param priority : 1-based priority - */ - private ToDoItem itemWithPriorityElse(int priority, final ToDoItem itemElse) { - if(priority < 1) { - return null; - } - final List<ToDoItem> items = sortedNotYetComplete(); - if(priority > items.size()) { - return null; - } - return priority>=0 && items.size()>=priority? items.get(priority-1): itemElse; - } - //endregion - - //region > similarTo (contributed collection) - @ActionLayout( - contributed = Contributed.AS_ASSOCIATION - ) - @Action(semantics = SemanticsOf.SAFE) - public List<ToDoItem> similarTo(final ToDoItem toDoItem) { - final List<ToDoItem> similarToDoItems = allMatches( - new QueryDefault<ToDoItem>(ToDoItem.class, - "findByOwnedByAndCategory", - "ownedBy", currentUserName(), - "category", toDoItem.getCategory())); - return Lists.newArrayList(Iterables.filter(similarToDoItems, excluding(toDoItem))); - } - - - private static Predicate<ToDoItem> excluding(final ToDoItem toDoItem) { - return new Predicate<ToDoItem>() { - @Override - public boolean apply(ToDoItem input) { - return input != toDoItem; - } - }; - } - //endregion - - //region > updateCategory (contributed action) - - @ActionLayout( - describedAs = "Update category and subcategory" - ) - @Action(semantics = SemanticsOf.IDEMPOTENT) - public Categorized updateCategory( - final Categorized item, - final @ParameterLayout(named="Category") Category category, - final @Optional @ParameterLayout(named="Subcategory") Subcategory subcategory) { - item.setCategory(category); - item.setSubcategory(subcategory); - return item; - } - public Category default1UpdateCategory( - final Categorized item) { - return item != null? item.getCategory(): null; - } - public Subcategory default2UpdateCategory( - final Categorized item) { - return item != null? item.getSubcategory(): null; - } - - public List<Subcategory> choices2UpdateCategory( - final Categorized item, final Category category) { - return Subcategory.listFor(category); - } - - public String validateUpdateCategory( - final Categorized item, final Category category, final Subcategory subcategory) { - return Subcategory.validate(category, subcategory); - } - //endregion - - // region > exportAsJson (action) - /** - * Demonstrates functionality of streaming back Clob/Blob result within an action with a prompt, i.e. Ajax request - */ - @Action(semantics = SemanticsOf.SAFE) - public Clob exportAsJson( - final ToDoItem toDoItem, - @ParameterLayout(named = "File name") String fileName - ) { - if(!fileName.endsWith(".json")) { - fileName += ".json"; - } - return new Clob( - fileName, - "application/json", - "{" + - "${symbol_escape}"description${symbol_escape}": ${symbol_escape}"" + toDoItem.getDescription()+"${symbol_escape}"" + - ",${symbol_escape}"complete${symbol_escape}": " + ""+toDoItem.isComplete() + - "}"); - } - - public String default1ExportAsJson() { - return "todo"; - } - //endregion - - - //region > helpers - protected String currentUserName() { - return getContainer().getUser().getName(); - } - //endregion - - //region > injected services - @javax.inject.Inject - private ToDoItems toDoItems; - - @javax.inject.Inject - private QueryResultsCache queryResultsCache; - //endregion - -} http://git-wip-us.apache.org/repos/asf/isis/blob/a4ec0b72/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemSubscriptions.java ---------------------------------------------------------------------- diff --git a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemSubscriptions.java b/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemSubscriptions.java deleted file mode 100644 index ea76566..0000000 --- a/example/archetype/todoapp/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemSubscriptions.java +++ /dev/null @@ -1,402 +0,0 @@ -#set( $symbol_pound = '#' ) -#set( $symbol_dollar = '$' ) -#set( $symbol_escape = '\' ) -/* - * 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. - */ -package dom.todo; - -import java.util.EventObject; -import java.util.List; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import com.google.common.base.Function; -import com.google.common.base.Predicate; -import com.google.common.collect.Lists; -import com.google.common.eventbus.Subscribe; -import org.apache.isis.applib.DomainObjectContainer; -import org.apache.isis.applib.NonRecoverableException; -import org.apache.isis.applib.RecoverableException; -import org.apache.isis.applib.annotation.Action; -import org.apache.isis.applib.annotation.ActionLayout; -import org.apache.isis.applib.annotation.DomainService; -import org.apache.isis.applib.annotation.DomainServiceLayout; -import org.apache.isis.applib.annotation.MemberOrder; -import org.apache.isis.applib.annotation.NatureOfService; -import org.apache.isis.applib.annotation.ParameterLayout; -import org.apache.isis.applib.annotation.Programmatic; -import org.apache.isis.applib.annotation.RestrictTo; -import org.apache.isis.applib.annotation.SemanticsOf; -import org.apache.isis.applib.services.eventbus.ActionDomainEvent; -import org.apache.isis.applib.services.eventbus.CollectionDomainEvent; -import org.apache.isis.applib.services.eventbus.EventBusService; -import org.apache.isis.applib.services.eventbus.PropertyDomainEvent; - -import static com.google.common.collect.Iterables.filter; -import static com.google.common.collect.Iterables.transform; -import static com.google.common.collect.Lists.newArrayList; - -/** - * Subscribes to changes made to the {@link dom.todo.ToDoItem} entity. - * - * <p> - * (For demo purposes) the behaviour can be influenced using {@link ${symbol_pound}subscriberBehaviour(dom.todo.ToDoItemSubscriptions.Behaviour)}. - * In particular, the subscriber can be used to hide/disable/validate actions, or just to perform pre- or post-execute - * tasks. This also includes being set to throw an exception during the execution of the action (also in effect - * vetoing the change). - * </p> - */ -@DomainService(nature = NatureOfService.VIEW_MENU_ONLY) -@DomainServiceLayout(menuBar = DomainServiceLayout.MenuBar.SECONDARY, menuOrder = "30") -public class ToDoItemSubscriptions { - - //region > LOG - private final static org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(ToDoItemSubscriptions.class); - //endregion - - //region > postConstruct, preDestroy - - /** - * Registers this service with the {@link org.apache.isis.applib.services.eventbus.EventBusService}. - * - * <p> - * Because this service is a singleton, this is called during initial bootstrap. - * </p> - */ - @Programmatic - @PostConstruct - public void postConstruct() { - LOG.info("postConstruct: registering to event bus"); - eventBusService.register(this); - } - - /** - * Unregisters this service from the {@link org.apache.isis.applib.services.eventbus.EventBusService}. - * - * <p> - * Because this service is a singleton, this is only done when the system is shutdown. - * </p> - */ - @Programmatic - @PreDestroy - public void preDestroy() { - LOG.info("preDestroy: unregistering from event bus"); - eventBusService.unregister(this); - } - //endregion - - - //region > on(Event)... - - public static enum Behaviour { - AnyExecuteAccept, - AnyExecuteVetoWithRecoverableException, - AnyExecuteVetoWithNonRecoverableException, - AnyExecuteVetoWithOtherException, - UpdateCostActionHide, - UpdateCostActionDisable, - UpdateCostActionInvalidate, - DescriptionPropertyHide, - DescriptionPropertyDisable, - DescriptionPropertyInvalidate, - DependenciesCollectionHide, - // not implemented in Wicket viewer, but supported in wrapped objects - DependenciesCollectionDisable, - // not implemented in Wicket viewer, but supported in wrapped objects - DependenciesCollectionInvalidateAdd, - DependenciesCollectionInvalidateRemove, - SimilarToCollectionHide - } - - /** - * The desired behaviour of this service. - */ - private Behaviour behaviour = Behaviour.AnyExecuteAccept; - - /** - * To demo/test what occurs if a subscriber that might veto an event. - */ - @MemberOrder(name = "Prototyping", sequence = "80") - @ActionLayout( - named="Set subscriber behaviour" - ) - @Action( - semantics = SemanticsOf.IDEMPOTENT, - restrictTo = RestrictTo.PROTOTYPING - ) - public void subscriberBehaviour( - @ParameterLayout( - named="Behaviour" - ) - final Behaviour behaviour) { - this.behaviour = behaviour; - container.informUser("Subscriber behaviour set to: " + behaviour); - } - public Behaviour default0SubscriberBehaviour() { - return this.behaviour; - } - - @Programmatic - public Behaviour getSubscriberBehaviour() { - return behaviour; - } - - - private void onExecutedThrowExceptionIfSet(final ActionDomainEvent<?> ev) { - if(ev != null && ev.getSemantics().isSafe()) { - return; - } - onExecutedThrowExceptionIfSet(); - } - private void onExecutedThrowExceptionIfSet(final PropertyDomainEvent<?, ?> ev) { - onExecutedThrowExceptionIfSet(); - } - private void onExecutedThrowExceptionIfSet(final CollectionDomainEvent<?, ?> ev) { - onExecutedThrowExceptionIfSet(); - } - - - private void onExecutedThrowExceptionIfSet() { - if(behaviour == Behaviour.AnyExecuteVetoWithRecoverableException) { - throw new RecoverableException("Rejecting event (recoverable exception thrown)"); - } - if(behaviour == Behaviour.AnyExecuteVetoWithNonRecoverableException) { - throw new NonRecoverableException("Rejecting event (non-recoverable exception thrown)"); - } - if(behaviour == Behaviour.AnyExecuteVetoWithOtherException) { - throw new RuntimeException("Throwing some other exception"); - } - } - //endregion - - //region > on(Event) for ToDoItem-specific events - @Programmatic - @Subscribe - public void on(final ToDoItem.CompletedEvent ev) { - recordEvent(ev); - switch(ev.getEventPhase()) { - case HIDE: - break; - case DISABLE: - break; - case VALIDATE: - break; - case EXECUTING: - break; - case EXECUTED: - LOG.info("Received ToDoItem.CompletedEvent for : " + ev.getSource().toString()); - break; - } - } - //endregion - - //region > on(Event) ... general purpose - - @Programmatic - @Subscribe - public void on(final ActionDomainEvent<?> ev) { - recordEvent(ev); - switch(ev.getEventPhase()) { - case HIDE: - if(getSubscriberBehaviour() == Behaviour.UpdateCostActionHide) { - if(ev.getIdentifier().getMemberName().equals("updateCost")) { - ev.hide(); - } - } - break; - case DISABLE: - if(getSubscriberBehaviour() == Behaviour.UpdateCostActionDisable) { - if(ev.getIdentifier().getMemberName().equals("updateCost")) { - ev.disable("ToDoItemSubscriptions says: updateCost action disabled!"); - } - } - break; - case VALIDATE: - if(getSubscriberBehaviour() == Behaviour.UpdateCostActionInvalidate && - ev.getIdentifier().getMemberName().equals("updateCost")) { - ev.invalidate("ToDoItemSubscriptions says: can't invoke updateCost action with these args!"); - } - break; - case EXECUTING: - break; - case EXECUTED: - LOG.info("Received ActionDomainEvent, " + ev.getSource().toString() + ", invoked " + ev.getIdentifier().getMemberName()); - onExecutedThrowExceptionIfSet(ev); - break; - } - } - - @Programmatic - @Subscribe - public void on(PropertyDomainEvent<?,?> ev) { - recordEvent(ev); - switch(ev.getEventPhase()) { - case HIDE: - if(getSubscriberBehaviour() == Behaviour.DescriptionPropertyHide && - ev.getIdentifier().getMemberName().equals("description")) { - ev.veto(""); - } - break; - case DISABLE: - if(getSubscriberBehaviour() == Behaviour.DescriptionPropertyDisable && - ev.getIdentifier().getMemberName().equals("description")) { - ev.veto("ToDoItemSubscriptions says: description property disabled!"); - } - break; - case VALIDATE: - if(getSubscriberBehaviour() == Behaviour.DescriptionPropertyInvalidate && - ev.getIdentifier().getMemberName().equals("description")) { - ev.veto("ToDoItemSubscriptions says: can't change description property to this value!"); - } - break; - case EXECUTING: - break; - case EXECUTED: - LOG.info("Received PropertyDomainEvent, " + ev.getSource().toString() + ", changed " + ev.getIdentifier().getMemberName() + " : " + ev.getOldValue() + " -> " + ev.getNewValue()); - onExecutedThrowExceptionIfSet(ev); - - if(ev.getIdentifier().getMemberName().contains("description")) { - String newValue = (String) ev.getNewValue(); - if(newValue.matches(".*demo veto.*")) { - throw new RecoverableException("oh no you don't! " + ev.getNewValue()); - } - } - break; - } - } - - @Programmatic - @Subscribe - public void on(CollectionDomainEvent<?,?> ev) { - recordEvent(ev); - switch (ev.getEventPhase()) { - case HIDE: - if(getSubscriberBehaviour() == Behaviour.DependenciesCollectionHide && - ev.getIdentifier().getMemberName().equals("dependencies")) { - ev.veto(""); - } - if (getSubscriberBehaviour() == Behaviour.SimilarToCollectionHide && - ev.getIdentifier().getMemberName().equals("similarTo")) { - ev.veto(""); - } - break; - case DISABLE: - if (getSubscriberBehaviour() == Behaviour.DependenciesCollectionDisable && - ev.getIdentifier().getMemberName().equals("dependencies")) { - ev.veto("ToDoItemSubscriptions says: dependencies collection disabled!"); - } - break; - case VALIDATE: - if(getSubscriberBehaviour() == Behaviour.DependenciesCollectionInvalidateAdd && - ev.getIdentifier().getMemberName().equals("dependencies") && - ev.getOf() == CollectionDomainEvent.Of.ADD_TO ) { - ev.veto("ToDoItemSubscriptions says: can't add this object to dependencies collection!"); - } - if(getSubscriberBehaviour() == Behaviour.DependenciesCollectionInvalidateRemove && - ev.getIdentifier().getMemberName().equals("dependencies") && - ev.getOf() == CollectionDomainEvent.Of.REMOVE_FROM ) { - ev.veto("ToDoItemSubscriptions says: can't remove this object from dependencies collection!"); - } - break; - case EXECUTING: - break; - case EXECUTED: - if(ev.getOf() == CollectionDomainEvent.Of.ADD_TO) { - LOG.info("Received CollectionDomainEvent, " + ev.getSource().toString() + ", added to " + ev.getIdentifier().getMemberName() + " : " + ev.getValue()); - } else { - LOG.info("Received CollectionDomainEvent, " + ev.getSource().toString() + ", removed from " + ev.getIdentifier().getMemberName() + " : " + ev.getValue()); - } - onExecutedThrowExceptionIfSet(ev); - break; - } - - } - - //endregion - - //region > receivedEvents - private final List<java.util.EventObject> receivedEvents = Lists.newLinkedList(); - - /** - * Used in integration tests. - */ - @Programmatic - public List<java.util.EventObject> receivedEvents() { - return receivedEvents; - } - - /** - * Used in integration tests. - */ - @Programmatic - public <T extends java.util.EventObject> List<T> receivedEvents(final Class<T> expectedType) { - return newArrayList( - transform( - filter(receivedEvents, instanceOf(expectedType)), - castTo(expectedType))); - } - - private static <T extends EventObject> Function<EventObject, T> castTo(Class<T> expectedType) { - return new Function<EventObject, T>() { - @Override - public T apply(EventObject input) { - return (T) input; - } - }; - } - - private static <T extends EventObject> Predicate<EventObject> instanceOf(final Class<T> expectedType) { - return new Predicate<EventObject>() { - @Override - public boolean apply(EventObject input) { - return expectedType.isInstance(input); - } - }; - } - - /** - * Used in integration tests. - */ - @Programmatic - public <T extends java.util.EventObject> T mostRecentlyReceivedEvent(Class<T> expectedType) { - final List<T> receivedEvents = receivedEvents(expectedType); - return !receivedEvents.isEmpty() ? receivedEvents.get(0) : null; - } - private void recordEvent(final java.util.EventObject ev) { - receivedEvents.add(0, ev); - } - /** - * Used in integration tests. - */ - @Programmatic - public void reset() { - receivedEvents.clear(); - subscriberBehaviour(ToDoItemSubscriptions.Behaviour.AnyExecuteAccept); - } - //endregion - - //region > injected services - @javax.inject.Inject - private DomainObjectContainer container; - - @javax.inject.Inject - private EventBusService eventBusService; - //endregion - - -}
