001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.isis.core.metamodel.layoutmetadata.json; 018 019import java.io.IOException; 020import java.util.Collections; 021import java.util.Comparator; 022import java.util.List; 023import java.util.Map; 024import java.util.Properties; 025import java.util.Set; 026 027import com.google.common.base.Function; 028import com.google.common.base.Joiner; 029import com.google.common.base.Strings; 030import com.google.common.collect.Iterables; 031import com.google.common.collect.Lists; 032import com.google.common.collect.Maps; 033import com.google.common.collect.Sets; 034import com.google.gson.Gson; 035import com.google.gson.GsonBuilder; 036 037import org.apache.isis.applib.annotation.MemberGroupLayout.ColumnSpans; 038import org.apache.isis.applib.annotation.Render; 039import org.apache.isis.applib.annotation.Render.Type; 040import org.apache.isis.applib.annotation.When; 041import org.apache.isis.applib.annotation.Where; 042import org.apache.isis.applib.filter.Filter; 043import org.apache.isis.applib.filter.Filters; 044import org.apache.isis.applib.services.memento.MementoService.Memento; 045import org.apache.isis.core.commons.lang.ClassExtensions; 046import org.apache.isis.core.metamodel.facets.describedas.DescribedAsFacet; 047import org.apache.isis.core.metamodel.facets.hide.HiddenFacet; 048import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet; 049import org.apache.isis.core.metamodel.facets.members.order.MemberOrderFacet; 050import org.apache.isis.core.metamodel.facets.members.resolve.RenderFacet; 051import org.apache.isis.core.metamodel.facets.multiline.MultiLineFacet; 052import org.apache.isis.core.metamodel.facets.named.NamedFacet; 053import org.apache.isis.core.metamodel.facets.object.membergroups.MemberGroupLayoutFacet; 054import org.apache.isis.core.metamodel.facets.object.paged.PagedFacet; 055import org.apache.isis.core.metamodel.facets.typicallen.TypicalLengthFacet; 056import org.apache.isis.core.metamodel.layout.memberorderfacet.MemberOrderFacetComparator; 057import org.apache.isis.core.metamodel.layoutmetadata.ActionRepr; 058import org.apache.isis.core.metamodel.layoutmetadata.ColumnRepr; 059import org.apache.isis.core.metamodel.layoutmetadata.CssClassFacetRepr; 060import org.apache.isis.core.metamodel.layoutmetadata.DescribedAsFacetRepr; 061import org.apache.isis.core.metamodel.layoutmetadata.DisabledFacetRepr; 062import org.apache.isis.core.metamodel.layoutmetadata.HiddenFacetRepr; 063import org.apache.isis.core.metamodel.layoutmetadata.LayoutMetadata; 064import org.apache.isis.core.metamodel.layoutmetadata.LayoutMetadataReader; 065import org.apache.isis.core.metamodel.layoutmetadata.MemberGroupRepr; 066import org.apache.isis.core.metamodel.layoutmetadata.MemberRepr; 067import org.apache.isis.core.metamodel.layoutmetadata.MultiLineFacetRepr; 068import org.apache.isis.core.metamodel.layoutmetadata.NamedFacetRepr; 069import org.apache.isis.core.metamodel.layoutmetadata.PagedFacetRepr; 070import org.apache.isis.core.metamodel.layoutmetadata.RenderFacetRepr; 071import org.apache.isis.core.metamodel.layoutmetadata.TypicalLengthFacetRepr; 072import org.apache.isis.core.metamodel.spec.ActionType; 073import org.apache.isis.core.metamodel.spec.ObjectSpecification; 074import org.apache.isis.core.metamodel.spec.ObjectSpecifications; 075import org.apache.isis.core.metamodel.spec.ObjectSpecifications.MemberGroupLayoutHint; 076import org.apache.isis.core.metamodel.spec.feature.Contributed; 077import org.apache.isis.core.metamodel.spec.feature.ObjectAction; 078import org.apache.isis.core.metamodel.spec.feature.ObjectActions; 079import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation; 080import org.apache.isis.core.metamodel.spec.feature.ObjectMember; 081import org.apache.isis.core.progmodel.facets.members.disabled.DisabledFacet; 082import org.apache.isis.core.progmodel.facets.members.disabled.DisabledFacetImpl; 083import org.apache.isis.core.progmodel.facets.members.disabled.annotation.DisabledFacetAnnotation; 084import org.apache.isis.core.progmodel.facets.members.disabled.annotation.DisabledFacetFromProperties; 085 086public class LayoutMetadataReaderFromJson implements LayoutMetadataReader { 087 088 public Properties asProperties(Class<?> domainClass) { 089 LayoutMetadata metadata; 090 try { 091 metadata = readMetadata(domainClass); 092 } catch (Exception e) { 093 throw new ReaderException("Failed to locate/parse " + domainClass.getName() + ".layout.json file (" + e.getMessage() + ")", e); 094 } 095 if(metadata.getColumns() == null || metadata.getColumns().size() != 4) { 096 throw new ReaderException("JSON metadata must have precisely 4 columns (prop/prop/prop/coll)"); 097 } 098 099 final Properties props = new Properties(); 100 101 setMemberGroupLayoutColumnSpans(metadata, props); 102 setMemberGroupLayoutColumnLists(metadata, 0, "left", props); 103 setMemberGroupLayoutColumnLists(metadata, 1, "middle", props); 104 setMemberGroupLayoutColumnLists(metadata, 2, "right", props); 105 106 int[] memberSeq = {0}; 107 setProperties(metadata, props, memberSeq); 108 setCollections(metadata, props, memberSeq); 109 setFreestandingActions(metadata, props); 110 111 return props; 112 } 113 114 private static void setMemberGroupLayoutColumnSpans(LayoutMetadata metadata, final Properties props) { 115 final List<ColumnRepr> columns = metadata.getColumns(); 116 final String columnSpansStr = Joiner.on(",").join(Iterables.transform(columns, new Function<ColumnRepr,Integer>(){ 117 @Override 118 public Integer apply(ColumnRepr input) { 119 return input.span; 120 }})); 121 props.setProperty("class.memberGroupLayout.columnSpans", columnSpansStr); 122 } 123 124 private static void setMemberGroupLayoutColumnLists(LayoutMetadata metadata, int colIdx, String propkey, Properties props) { 125 final ColumnRepr column = metadata.getColumns().get(colIdx); 126 final Map<String, MemberGroupRepr> memberGroups = column.memberGroups; 127 final String val = memberGroups != null ? Joiner.on(",").join(memberGroups.keySet()) : ""; 128 props.setProperty("class.memberGroupLayout." + propkey, val); 129 } 130 131 private static void setProperties(LayoutMetadata metadata, Properties props, int[] memberSeq) { 132 final List<ColumnRepr> columns = metadata.getColumns(); 133 for (final ColumnRepr columnRepr : columns) { 134 final Map<String, MemberGroupRepr> memberGroups = columnRepr.memberGroups; 135 136 if(memberGroups == null) { 137 continue; 138 } 139 140 for (final String memberGroupName : memberGroups.keySet()) { 141 final MemberGroupRepr memberGroup = memberGroups.get(memberGroupName); 142 final Map<String, MemberRepr> members = memberGroup.members; 143 144 if(members == null) { 145 continue; 146 } 147 setMembersAndAssociatedActions(props, memberGroupName, members, memberSeq); 148 } 149 } 150 } 151 152 private static void setCollections(LayoutMetadata metadata, Properties props, int[] memberSeq) { 153 final ColumnRepr columnRepr = metadata.getColumns().get(3); 154 final Map<String, MemberRepr> collections = columnRepr.collections; 155 setMembersAndAssociatedActions(props, null, collections, memberSeq); 156 } 157 158 private static void setMembersAndAssociatedActions(Properties props, final String memberGroupName, final Map<String, MemberRepr> members, int[] memberSeq) { 159 for(final String memberName: members.keySet()) { 160 props.setProperty("member." + memberName + ".memberOrder.sequence", ""+ ++memberSeq[0]); 161 if(memberGroupName != null) { 162 props.setProperty("member." + memberName + ".memberOrder.name", memberGroupName); 163 } 164 165 final MemberRepr memberRepr = members.get(memberName); 166 167 final NamedFacetRepr named = memberRepr.named; 168 if(named != null) { 169 props.setProperty("member." + memberName + ".named.value", named.value); 170 } 171 final DescribedAsFacetRepr describedAs = memberRepr.describedAs; 172 if(describedAs!= null) { 173 props.setProperty("member." + memberName + ".describedAs.value", describedAs.value); 174 } 175 final CssClassFacetRepr cssClass = memberRepr.cssClass; 176 if(cssClass!= null) { 177 props.setProperty("member." + memberName + ".cssClass.value", cssClass.value); 178 } 179 final TypicalLengthFacetRepr typicalLength = memberRepr.typicalLength; 180 if(typicalLength!= null) { 181 props.setProperty("member." + memberName + ".typicalLength.value", ""+typicalLength.value); 182 } 183 final MultiLineFacetRepr multiLine = memberRepr.multiLine; 184 if(multiLine!= null) { 185 props.setProperty("member." + memberName + ".multiLine.numberOfLines", ""+multiLine.numberOfLines); 186 } 187 final PagedFacetRepr paged = memberRepr.paged; 188 if(paged != null) { 189 props.setProperty("member." + memberName + ".paged.value", ""+paged.value); 190 } 191 final DisabledFacetRepr disabled = memberRepr.disabled; 192 if(disabled != null) { 193 // same default as in Disabled.when() 194 final When disabledWhen = disabled.when!=null?disabled.when: When.ALWAYS; 195 props.setProperty("member." + memberName + ".disabled.when", disabledWhen.toString()); 196 // same default as in Disabled.where() 197 final Where disabledWhere = disabled.where!=null?disabled.where: Where.ANYWHERE; 198 props.setProperty("member." + memberName + ".disabled.where", disabledWhere.toString()); 199 // same default as in Disabled.reason() 200 final String disabledReason = disabled.reason!=null?disabled.reason: ""; 201 props.setProperty("member." + memberName + ".disabled.reason", disabledReason); 202 } 203 final HiddenFacetRepr hidden = memberRepr.hidden; 204 if(hidden != null) { 205 // same default as in Hidden.when() 206 final When hiddenWhen = hidden.when!=null?hidden.when: When.ALWAYS; 207 props.setProperty("member." + memberName + ".hidden.when", hiddenWhen.toString()); 208 // same default as in Hidden.where() 209 final Where hiddenWhere = hidden.where!=null?hidden.where: Where.ANYWHERE; 210 props.setProperty("member." + memberName + ".hidden.where", hiddenWhere.toString()); 211 } 212 final RenderFacetRepr render = memberRepr.render; 213 if(render != null) { 214 // same default as in Render.Type.value() 215 final Type renderType = render.value!=null?render.value: Render.Type.EAGERLY; 216 props.setProperty("member." + memberName + ".render.value", renderType.toString()); 217 } 218 219 final Map<String, ActionRepr> actions = memberRepr.actions; 220 if(actions != null) { 221 int actSeq = 0; 222 for(final String actionName: actions.keySet()) { 223 final ActionRepr actionRepr = actions.get(actionName); 224 String nameKey = "action." + actionName + ".memberOrder.name"; 225 props.setProperty(nameKey, memberName); 226 setRemainingActionProperties(props, "action", actionName, actionRepr, ++actSeq); 227 } 228 } 229 } 230 } 231 232 private static void setFreestandingActions(LayoutMetadata metadata, Properties props) { 233 if(metadata.getActions() == null) { 234 return; 235 } 236 int xeq=0; 237 final Map<String, ActionRepr> actions = metadata.getActions(); 238 for (final String actionName : actions.keySet()) { 239 final ActionRepr actionRepr = actions.get(actionName); 240 setRemainingActionProperties(props, "member", actionName, actionRepr, ++xeq); 241 } 242 } 243 244 private static void setRemainingActionProperties(Properties props, String prefix, final String actionNameOrig, final ActionRepr actionRepr, final int seq) { 245 final String actionName = actionNameOrig + ("action".equals(prefix)?"":"()"); 246 props.setProperty(prefix + "." + actionName + ".memberOrder.sequence", ""+ seq); 247 248 final NamedFacetRepr actionNamed = actionRepr.named; 249 if(actionNamed != null) { 250 props.setProperty(prefix +"." + actionName + ".named.value", actionNamed.value); 251 } 252 final DescribedAsFacetRepr describedAs = actionRepr.describedAs; 253 if(describedAs!= null) { 254 props.setProperty(prefix +"." + actionName + ".describedAs.value", describedAs.value); 255 } 256 final CssClassFacetRepr cssClass = actionRepr.cssClass; 257 if(cssClass!= null) { 258 props.setProperty(prefix +"." + actionName + ".cssClass.value", cssClass.value); 259 } 260 } 261 262 public LayoutMetadata asLayoutMetadata(Class<?> domainClass) throws ReaderException { 263 try { 264 return readMetadata(domainClass); 265 } catch (IOException e) { 266 throw new ReaderException(e); 267 } catch (RuntimeException e) { 268 throw new ReaderException(e); 269 } 270 } 271 272 // ////////////////////////////////////// 273 274 private LayoutMetadata readMetadata(Class<?> domainClass) throws IOException { 275 final String content = ClassExtensions.resourceContent(domainClass, ".layout.json"); 276 return readMetadata(content); 277 } 278 279 LayoutMetadata readMetadata(final String content) { 280 final Gson gson = new GsonBuilder().create(); 281 return gson.fromJson(content, LayoutMetadata.class); 282 } 283 284 // ////////////////////////////////////// 285 286 private final static MemberOrderFacetComparator memberOrderFacetComparator = new MemberOrderFacetComparator(false); 287 288 /** 289 * not API 290 */ 291 public String asJson(ObjectSpecification objectSpec) { 292 final LayoutMetadata metadata = new LayoutMetadata(); 293 metadata.setColumns(Lists.<ColumnRepr>newArrayList()); 294 295 final MemberGroupLayoutFacet mglf = objectSpec.getFacet(MemberGroupLayoutFacet.class); 296 final ColumnSpans columnSpans = mglf.getColumnSpans(); 297 298 Set<String> actionIdsForAssociations = Sets.newTreeSet(); 299 300 ColumnRepr columnRepr; 301 302 columnRepr = addColumnWithSpan(metadata, columnSpans.getLeft()); 303 updateColumnMemberGroups(objectSpec, MemberGroupLayoutHint.LEFT, columnRepr, actionIdsForAssociations); 304 305 columnRepr = addColumnWithSpan(metadata, columnSpans.getMiddle()); 306 updateColumnMemberGroups(objectSpec, MemberGroupLayoutHint.MIDDLE, columnRepr, actionIdsForAssociations); 307 308 columnRepr = addColumnWithSpan(metadata, columnSpans.getRight()); 309 updateColumnMemberGroups(objectSpec, MemberGroupLayoutHint.RIGHT, columnRepr, actionIdsForAssociations); 310 311 columnRepr = addColumnWithSpan(metadata, columnSpans.getCollections()); 312 updateCollectionColumnRepr(objectSpec, columnRepr, actionIdsForAssociations); 313 314 addActions(objectSpec, metadata, actionIdsForAssociations); 315 316 final Gson gson = new GsonBuilder().setPrettyPrinting().create(); 317 return gson.toJson(metadata); 318 } 319 320 private static void updateColumnMemberGroups(ObjectSpecification objectSpec, final MemberGroupLayoutHint hint, ColumnRepr columnRepr, Set<String> actionIdsForAssociations) { 321 final List<ObjectAssociation> objectAssociations = propertiesOf(objectSpec); 322 final Map<String, List<ObjectAssociation>> associationsByGroup = ObjectAssociation.Util.groupByMemberOrderName(objectAssociations); 323 324 final List<String> groupNames = ObjectSpecifications.orderByMemberGroups(objectSpec, associationsByGroup.keySet(), hint); 325 326 columnRepr.memberGroups = Maps.newLinkedHashMap(); 327 for (String groupName : groupNames) { 328 final MemberGroupRepr memberGroupRepr = new MemberGroupRepr(); 329 columnRepr.memberGroups.put(groupName, memberGroupRepr); 330 final List<ObjectAssociation> associationsInGroup = associationsByGroup.get(groupName); 331 memberGroupRepr.members = Maps.newLinkedHashMap(); 332 if(associationsInGroup == null) { 333 continue; 334 } 335 for (ObjectAssociation assoc : associationsInGroup) { 336 final MemberRepr memberRepr = newMemberRepr(objectSpec, assoc, actionIdsForAssociations); 337 memberGroupRepr.members.put(assoc.getId(), memberRepr); 338 } 339 } 340 } 341 private static void addActions(ObjectSpecification objectSpec, final LayoutMetadata metadata, Set<String> actionIdsForAssociations) { 342 Map<String, ActionRepr> actions = Maps.newLinkedHashMap(); 343 final List<ObjectAction> actionsOf = actionsOf(objectSpec, actionIdsForAssociations); 344 for(ObjectAction action: actionsOf) { 345 actions.put(action.getId(), newActionRepr(objectSpec, action)); 346 } 347 metadata.setActions(actions); 348 } 349 350 private static ActionRepr newActionRepr(ObjectSpecification objectSpec, ObjectAction action) { 351 ActionRepr actionRepr = new ActionRepr(); 352 353 CssClassFacet cssClassFacet = action.getFacet(CssClassFacet.class); 354 if(cssClassFacet != null && !cssClassFacet.isNoop()) { 355 CssClassFacetRepr cssClassFacetRepr = new CssClassFacetRepr(); 356 cssClassFacetRepr.value = cssClassFacet.value(); 357 actionRepr.cssClass = cssClassFacetRepr; 358 } 359 DescribedAsFacet describedAsFacet = action.getFacet(DescribedAsFacet.class); 360 if(describedAsFacet != null && !describedAsFacet.isNoop() && !Strings.isNullOrEmpty(describedAsFacet.value())) { 361 DescribedAsFacetRepr describedAsFacetRepr = new DescribedAsFacetRepr(); 362 describedAsFacetRepr.value = describedAsFacet.value(); 363 actionRepr.describedAs = describedAsFacetRepr; 364 } 365 NamedFacet namedFacet = action.getFacet(NamedFacet.class); 366 if(namedFacet != null && !namedFacet.isNoop()) { 367 NamedFacetRepr namedFacetRepr = new NamedFacetRepr(); 368 namedFacetRepr.value = namedFacet.value(); 369 actionRepr.named = namedFacetRepr; 370 } 371 372 return actionRepr; 373 } 374 375 private static void updateCollectionColumnRepr(ObjectSpecification objectSpec, ColumnRepr columnRepr, Set<String> actionIdsOfAssociations) { 376 final List<ObjectAssociation> objectAssociations = collectionsOf(objectSpec); 377 columnRepr.collections = Maps.newLinkedHashMap(); 378 for(ObjectAssociation assoc: objectAssociations) { 379 final MemberRepr memberRepr = newMemberRepr(objectSpec, assoc, actionIdsOfAssociations); 380 columnRepr.collections.put(assoc.getId(), memberRepr); 381 } 382 } 383 384 385 private static MemberRepr newMemberRepr(ObjectSpecification objectSpec, ObjectAssociation assoc, Set<String> actionIdsForAssociations) { 386 final MemberRepr memberRepr = new MemberRepr(); 387 388 CssClassFacet cssClassFacet = assoc.getFacet(CssClassFacet.class); 389 if(cssClassFacet != null && !cssClassFacet.isNoop()) { 390 CssClassFacetRepr cssClassFacetRepr = new CssClassFacetRepr(); 391 cssClassFacetRepr.value = cssClassFacet.value(); 392 memberRepr.cssClass = cssClassFacetRepr; 393 } 394 DescribedAsFacet describedAsFacet = assoc.getFacet(DescribedAsFacet.class); 395 if(describedAsFacet != null && !describedAsFacet.isNoop() && !Strings.isNullOrEmpty(describedAsFacet.value())) { 396 DescribedAsFacetRepr describedAsFacetRepr = new DescribedAsFacetRepr(); 397 describedAsFacetRepr.value = describedAsFacet.value(); 398 memberRepr.describedAs = describedAsFacetRepr; 399 } 400 NamedFacet namedFacet = assoc.getFacet(NamedFacet.class); 401 if(namedFacet != null && !namedFacet.isNoop()) { 402 NamedFacetRepr namedFacetRepr = new NamedFacetRepr(); 403 namedFacetRepr.value = namedFacet.value(); 404 memberRepr.named = namedFacetRepr; 405 } 406 DisabledFacet disabledFacet = assoc.getFacet(DisabledFacet.class); 407 if(disabledFacet != null && !disabledFacet.isNoop()) { 408 DisabledFacetRepr disabledFacetRepr = new DisabledFacetRepr(); 409 if(disabledFacet instanceof DisabledFacetImpl) { 410 DisabledFacetImpl disabledFacetImpl = (DisabledFacetImpl) disabledFacet; 411 disabledFacetRepr.reason = Strings.emptyToNull(disabledFacetImpl.getReason()); 412 } 413 disabledFacetRepr.when = whenAlwaysToNull(disabledFacet.when()); 414 disabledFacetRepr.where = whereAnywhereToNull(disabledFacet.where()); 415 memberRepr.disabled = disabledFacetRepr; 416 } 417 HiddenFacet hiddenFacet = assoc.getFacet(HiddenFacet.class); 418 if(hiddenFacet != null && !hiddenFacet.isNoop()) { 419 HiddenFacetRepr hiddenFacetRepr = new HiddenFacetRepr(); 420 hiddenFacetRepr.when = whenAlwaysToNull(hiddenFacet.when()); 421 hiddenFacetRepr.where = whereAnywhereToNull(hiddenFacet.where()); 422 memberRepr.hidden = hiddenFacetRepr; 423 } 424 MultiLineFacet multiLineFacet = assoc.getFacet(MultiLineFacet.class); 425 if(multiLineFacet != null && !multiLineFacet.isNoop()) { 426 MultiLineFacetRepr multiLineFacetRepr = new MultiLineFacetRepr(); 427 multiLineFacetRepr.numberOfLines = multiLineFacet.numberOfLines(); 428 memberRepr.multiLine = multiLineFacetRepr; 429 } 430 PagedFacet pagedFacet = assoc.getFacet(PagedFacet.class); 431 if(pagedFacet != null && !pagedFacet.isNoop()) { 432 PagedFacetRepr pagedFacetRepr = new PagedFacetRepr(); 433 pagedFacetRepr.value = pagedFacet.value(); 434 memberRepr.paged = pagedFacetRepr; 435 } 436 RenderFacet renderFacet = assoc.getFacet(RenderFacet.class); 437 if(renderFacet != null && !renderFacet.isNoop()) { 438 RenderFacetRepr renderFacetRepr = new RenderFacetRepr(); 439 renderFacetRepr.value = renderFacet.value(); 440 memberRepr.render = renderFacetRepr; 441 } 442 TypicalLengthFacet typicalLengthFacet = assoc.getFacet(TypicalLengthFacet.class); 443 if(typicalLengthFacet != null && !typicalLengthFacet.isNoop()) { 444 TypicalLengthFacetRepr typicalLengthFacetRepr = new TypicalLengthFacetRepr(); 445 typicalLengthFacetRepr.value = typicalLengthFacet.value(); 446 memberRepr.typicalLength = typicalLengthFacetRepr; 447 } 448 449 final List<ObjectAction> actions = objectSpec.getObjectActions( 450 ActionType.USER, Contributed.INCLUDED, ObjectAction.Filters.memberOrderOf(assoc)); 451 if(!actions.isEmpty()) { 452 memberRepr.actions = Maps.newLinkedHashMap(); 453 454 sortByMemberOrderFacet(actions); 455 456 for (final ObjectAction action : actions) { 457 final String actionId = action.getId(); 458 memberRepr.actions.put(actionId, new ActionRepr()); 459 actionIdsForAssociations.add(actionId); 460 } 461 } 462 return memberRepr; 463 } 464 465 private static Where whereAnywhereToNull(Where where) { 466 return where != Where.ANYWHERE? where: null; 467 } 468 469 private static When whenAlwaysToNull(When when) { 470 return when != When.ALWAYS? when: null; 471 } 472 473 private static void sortByMemberOrderFacet(final List<ObjectAction> actions) { 474 Collections.sort(actions, new Comparator<ObjectAction>() { 475 476 @Override 477 public int compare(ObjectAction o1, ObjectAction o2) { 478 final MemberOrderFacet m1 = o1.getFacet(MemberOrderFacet.class); 479 final MemberOrderFacet m2 = o2.getFacet(MemberOrderFacet.class); 480 return memberOrderFacetComparator.compare(m1, m2); 481 }}); 482 } 483 484 private static ColumnRepr addColumnWithSpan(final LayoutMetadata metadata, final int span) { 485 final ColumnRepr col = new ColumnRepr(); 486 metadata.getColumns().add(col); 487 col.span = span; 488 return col; 489 } 490 491 492 private static List<ObjectAssociation> propertiesOf(final ObjectSpecification objSpec) { 493 return objSpec.getAssociations(Contributed.EXCLUDED, ObjectAssociation.Filters.PROPERTIES); 494 } 495 private static List<ObjectAssociation> collectionsOf(final ObjectSpecification objSpec) { 496 return objSpec.getAssociations(Contributed.EXCLUDED, ObjectAssociation.Filters.COLLECTIONS); 497 } 498 private static List<ObjectAction> actionsOf(final ObjectSpecification objSpec, final Set<String> excludedActionIds) { 499 return objSpec.getObjectActions(ActionType.ALL, Contributed.INCLUDED, excluding(excludedActionIds)); 500 } 501 502 @SuppressWarnings({ "deprecation" }) 503 private static Filter<ObjectAction> excluding(final Set<String> excludedActionIds) { 504 return new Filter<ObjectAction>(){ 505 @Override 506 public boolean accept(ObjectAction t) { 507 return !excludedActionIds.contains(t.getId()); 508 } 509 }; 510 } 511 512 @Override 513 public String toString() { 514 return getClass().getName(); 515 } 516 517}