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.wicket.model; 018 019import java.io.Serializable; 020 021import org.apache.wicket.Component; 022 023/** 024 * A simple compound model which uses the component's name as the property expression to retrieve 025 * properties on the nested model object. 026 * 027 * CompoundPropertyModel is a chaining model so it will call get/setobject on the given object if 028 * the object is an instanceof IModel itself. 029 * 030 * @see org.apache.wicket.model.IModel 031 * @see org.apache.wicket.model.Model 032 * @see org.apache.wicket.model.LoadableDetachableModel 033 * @see ChainingModel 034 * 035 * @author Jonathan Locke 036 * 037 * @param <T> 038 * The model object type 039 */ 040public class CompoundPropertyModel<T> extends ChainingModel<T> implements IComponentInheritedModel<T> 041{ 042 private static final long serialVersionUID = 1L; 043 044 /** 045 * Constructor 046 * 047 * @param model 048 * The model 049 */ 050 public CompoundPropertyModel(final IModel<T> model) 051 { 052 super(model); 053 } 054 055 /** 056 * Constructor 057 * 058 * @param object 059 * The model object 060 */ 061 public CompoundPropertyModel(final T object) 062 { 063 super(object); 064 } 065 066 /** 067 * Returns the property expression that should be used against the target object 068 * 069 * @param component 070 * @return property expression that should be used against the target object 071 */ 072 protected String propertyExpression(Component component) 073 { 074 return component.getId(); 075 } 076 077 @Override 078 public <C> IWrapModel<C> wrapOnInheritance(Component component) 079 { 080 return new AttachedCompoundPropertyModel<C>(component); 081 } 082 083 /** 084 * Binds this model to a special property by returning a model that has this compound model as 085 * its nested/wrapped model and the property which should be evaluated. This can be used if the 086 * id of the Component isn't a valid property for the data object. 087 * 088 * @param property 089 * the name that will be used to find 090 * @return The IModel that is a wrapper around the current model and the property 091 * @param <S> 092 * the type of the property 093 */ 094 public <S> IModel<S> bind(String property) 095 { 096 return new PropertyModel<>(this, property); 097 } 098 099 /** 100 * Component aware variation of the {@link CompoundPropertyModel} that components that inherit 101 * the model get 102 * 103 * @author ivaynberg 104 * @param <C> 105 * The model object type 106 */ 107 private class AttachedCompoundPropertyModel<C> extends AbstractPropertyModel<C> 108 implements 109 IWrapModel<C> 110 { 111 private static final long serialVersionUID = 1L; 112 113 private final Component owner; 114 115 /** 116 * Constructor 117 * 118 * @param owner 119 * component that this model has been attached to 120 */ 121 AttachedCompoundPropertyModel(Component owner) 122 { 123 super(CompoundPropertyModel.this); 124 this.owner = owner; 125 } 126 127 @Override 128 protected String propertyExpression() 129 { 130 return CompoundPropertyModel.this.propertyExpression(owner); 131 } 132 133 @Override 134 public IModel<T> getWrappedModel() 135 { 136 return CompoundPropertyModel.this; 137 } 138 139 @Override 140 public void detach() 141 { 142 super.detach(); 143 CompoundPropertyModel.this.detach(); 144 } 145 } 146 147 /** 148 * Type-infering factory method 149 * 150 * @param <Z> 151 * the type of the model's object 152 * @param model 153 * model 154 * @return {@link CompoundPropertyModel} instance 155 */ 156 public static <Z> CompoundPropertyModel<Z> of(IModel<Z> model) 157 { 158 return new CompoundPropertyModel<>(model); 159 } 160 161 /** 162 * Type-infering factory method 163 * 164 * @param <Z> 165 * the type of the model's object 166 * @param object 167 * model object 168 * @return {@link CompoundPropertyModel} instance 169 */ 170 public static <Z extends Serializable> CompoundPropertyModel<Z> of(Z object) 171 { 172 return new CompoundPropertyModel<>(object); 173 } 174}