001 /**
002 * Copyright 2005-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.rice.krms.impl.repository;
017
018 import org.apache.commons.lang.StringUtils;
019 import org.kuali.rice.core.api.util.io.SerializationUtils;
020 import org.kuali.rice.krad.data.jpa.converters.BooleanYNConverter;
021 import org.kuali.rice.krad.data.jpa.PortableSequenceGenerator;
022 import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition;
023 import org.kuali.rice.krms.api.repository.context.ContextDefinition;
024 import org.kuali.rice.krms.api.repository.context.ContextDefinitionContract;
025
026 import javax.persistence.CascadeType;
027 import javax.persistence.Column;
028 import javax.persistence.Convert;
029 import javax.persistence.Entity;
030 import javax.persistence.FetchType;
031 import javax.persistence.GeneratedValue;
032 import javax.persistence.Id;
033 import javax.persistence.JoinColumn;
034 import javax.persistence.OneToMany;
035 import javax.persistence.Table;
036 import javax.persistence.Version;
037 import java.io.IOException;
038 import java.io.ObjectOutputStream;
039 import java.io.Serializable;
040 import java.util.ArrayList;
041 import java.util.HashMap;
042 import java.util.List;
043 import java.util.Map;
044
045 @Entity
046 @Table(name = "KRMS_CNTXT_T")
047 public class ContextBo implements ContextDefinitionContract, Serializable {
048
049 private static final long serialVersionUID = 1L;
050
051 public static final String CONTEXT_SEQ_NAME = "KRMS_CNTXT_S";
052
053 @PortableSequenceGenerator(name = CONTEXT_SEQ_NAME)
054 @GeneratedValue(generator = CONTEXT_SEQ_NAME)
055 @Id
056 @Column(name = "CNTXT_ID")
057 private String id;
058
059 @Column(name = "NM")
060 private String name;
061
062 @Column(name = "NMSPC_CD")
063 private String namespace;
064
065 @Column(name = "TYP_ID")
066 private String typeId;
067
068 @Column(name = "DESC_TXT")
069 private String description;
070
071 @Column(name = "ACTV")
072 @Convert(converter = BooleanYNConverter.class)
073 private boolean active = true;
074
075 @OneToMany(mappedBy = "context")
076 @JoinColumn(name = "CNTXT_ID", referencedColumnName = "CNTXT_ID", insertable = false, updatable = false)
077 private List<AgendaBo> agendas = new ArrayList<AgendaBo>();
078
079 @OneToMany(
080 targetEntity = ContextAttributeBo.class, orphanRemoval = true, mappedBy = "context",
081 cascade = { CascadeType.REFRESH, CascadeType.REMOVE, CascadeType.PERSIST },
082 fetch = FetchType.LAZY
083 )
084 @JoinColumn(name = "CNTXT_ID", referencedColumnName = "CNTXT_ID", insertable = true, updatable = true)
085 private List<ContextAttributeBo> attributeBos = new ArrayList<ContextAttributeBo>();
086
087 @Column(name = "VER_NBR")
088 @Version
089 private Long versionNumber;
090
091 @Override
092 public List<AgendaBo> getAgendas() {
093 return agendas;
094 }
095
096 @Override
097 public Map<String, String> getAttributes() {
098 Map<String, String> attributes = new HashMap<String, String>();
099
100 if (attributeBos != null) for (ContextAttributeBo attr : attributeBos) {
101 ((HashMap<String, String>) attributes).put(attr.getAttributeDefinition().getName(), attr.getValue());
102 }
103
104 return attributes;
105 }
106
107 public ContextBo copyContext(String additionalNameText) {
108 ContextBo copy = (ContextBo) SerializationUtils.deepCopy(this);
109
110 //
111 // set all IDs to null
112 //
113
114 copy.setId(null);
115
116 // copying a context does not copy the associated agendas
117 copy.setAgendas(null);
118 for (ContextAttributeBo attributeBo : copy.getAttributeBos()) {
119 attributeBo.setId(null);
120 }
121
122 if (!StringUtils.isEmpty(additionalNameText)) {
123 copy.setName(copy.getName() + additionalNameText);
124 }
125
126 return copy;
127 }
128
129 /**
130 * Converts a mutable bo to it's immutable counterpart
131 *
132 * @param bo the mutable business object
133 * @return the immutable object
134 */
135 public static ContextDefinition to(ContextBo bo) {
136 if (bo == null) {
137 return null;
138 }
139
140 return ContextDefinition.Builder.create(bo).build();
141 }
142
143 /**
144 * Converts a immutable object to it's mutable bo counterpart
145 *
146 * @param im immutable object
147 * @return the mutable bo
148 */
149 public static ContextBo from(ContextDefinition im) {
150 if (im == null) {
151 return null;
152 }
153
154 ContextBo bo = new ContextBo();
155 bo.id = im.getId();
156 bo.namespace = im.getNamespace();
157 bo.name = im.getName();
158 bo.typeId = im.getTypeId();
159 bo.description = im.getDescription();
160 bo.active = im.isActive();
161 bo.agendas = new ArrayList<AgendaBo>();
162 for (AgendaDefinition agenda : im.getAgendas()) {
163 bo.agendas.add(KrmsRepositoryServiceLocator.getAgendaBoService().from(agenda));
164 }
165
166 // build the list of agenda attribute BOs
167 List<ContextAttributeBo> attrs = new ArrayList<ContextAttributeBo>();
168
169 // for each converted pair, build an AgendaAttributeBo and add it to the list
170 ContextAttributeBo attributeBo;
171 for (Map.Entry<String, String> entry : im.getAttributes().entrySet()) {
172 KrmsAttributeDefinitionBo attrDefBo =
173 KrmsRepositoryServiceLocator.getKrmsAttributeDefinitionService().getKrmsAttributeBo(entry.getKey(), im.getNamespace());
174 attributeBo = new ContextAttributeBo();
175 attributeBo.setContext(bo);
176 attributeBo.setValue(entry.getValue());
177 attributeBo.setAttributeDefinition(attrDefBo);
178 attrs.add(attributeBo);
179 }
180
181 bo.setAttributeBos(attrs);
182 bo.versionNumber = im.getVersionNumber();
183
184 return bo;
185 }
186
187 /*
188 This is being done because there is a major issue with lazy relationships, in ensuring that the relationship is
189 still available after the object has been detached, or serialized. For most JPA providers, after serialization
190 any lazy relationship that was not instantiated will be broken, and either throw an error when accessed,
191 or return null.
192 */
193
194 private void writeObject(ObjectOutputStream stream) throws IOException, ClassNotFoundException {
195 agendas.size();
196 attributeBos.size();
197 stream.defaultWriteObject();
198 }
199
200 public String getId() {
201 return id;
202 }
203
204 public void setId(String id) {
205 this.id = id;
206 }
207
208 public String getName() {
209 return name;
210 }
211
212 public void setName(String name) {
213 this.name = name;
214 }
215
216 public String getNamespace() {
217 return namespace;
218 }
219
220 public void setNamespace(String namespace) {
221 this.namespace = namespace;
222 }
223
224 public String getTypeId() {
225 return typeId;
226 }
227
228 public void setTypeId(String typeId) {
229 this.typeId = typeId;
230 }
231
232 public String getDescription() {
233 return description;
234 }
235
236 public void setDescription(String description) {
237 this.description = description;
238 }
239
240 public boolean getActive() {
241 return active;
242 }
243
244 public boolean isActive() {
245 return active;
246 }
247
248 public void setActive(boolean active) {
249 this.active = active;
250 }
251
252 public void setAgendas(List<AgendaBo> agendas) {
253 this.agendas = agendas;
254 }
255
256 public List<ContextAttributeBo> getAttributeBos() {
257 return attributeBos;
258 }
259
260 public void setAttributeBos(List<ContextAttributeBo> attributeBos) {
261 this.attributeBos = attributeBos;
262 }
263
264 public Long getVersionNumber() {
265 return versionNumber;
266 }
267
268 public void setVersionNumber(Long versionNumber) {
269 this.versionNumber = versionNumber;
270 }
271 }