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}