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 */ 016package org.kuali.rice.krms.impl.repository; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.rice.core.api.util.io.SerializationUtils; 020import org.kuali.rice.krad.data.jpa.converters.BooleanYNConverter; 021import org.kuali.rice.krad.data.jpa.PortableSequenceGenerator; 022import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition; 023import org.kuali.rice.krms.api.repository.context.ContextDefinition; 024import org.kuali.rice.krms.api.repository.context.ContextDefinitionContract; 025 026import javax.persistence.CascadeType; 027import javax.persistence.Column; 028import javax.persistence.Convert; 029import javax.persistence.Entity; 030import javax.persistence.FetchType; 031import javax.persistence.GeneratedValue; 032import javax.persistence.Id; 033import javax.persistence.JoinColumn; 034import javax.persistence.OneToMany; 035import javax.persistence.Table; 036import javax.persistence.Version; 037import java.io.IOException; 038import java.io.ObjectOutputStream; 039import java.io.Serializable; 040import java.util.ArrayList; 041import java.util.HashMap; 042import java.util.List; 043import java.util.Map; 044 045@Entity 046@Table(name = "KRMS_CNTXT_T") 047public 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}