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    }