/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use * this file except in compliance with the License. You may obtain a copy of the License at the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing permissions and * limitations under the License. */ package org.apereo.portal.persondir.dao.jpa; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.persistence.Cacheable; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.SequenceGenerator; import javax.persistence.Table; import javax.persistence.TableGenerator; import javax.persistence.Version; import org.apereo.portal.persondir.ILocalAccountPerson; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; import org.hibernate.annotations.NaturalId; import org.springframework.util.Assert; @Entity @Table(name = "UP_PERSON_DIR") @SequenceGenerator( name = "UP_PERSON_DIR_GEN", sequenceName = "UP_PERSON_DIR_SEQ", allocationSize = 5 ) @TableGenerator(name = "UP_PERSON_DIR_GEN", pkColumnValue = "UP_PERSON_DIR", allocationSize = 5) @Cacheable @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) class LocalAccountPersonImpl implements Serializable, ILocalAccountPerson { private static final long serialVersionUID = 1L; @Id @GeneratedValue(generator = "UP_PERSON_DIR_GEN") @Column(name = "USER_DIR_ID") private final long id; @Version @Column(name = "ENTITY_VERSION") private final long entityVersion; @NaturalId @Column(name = "USER_NAME", length = 100, nullable = false) private final String name; @Column(name = "ENCRPTD_PSWD", length = 256) private String password; @Column(name = "LST_PSWD_CGH_DT") private Date lastPasswordChange; @OneToMany( targetEntity = LocalAccountPersonAttributeImpl.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true ) @JoinColumn(name = "USER_DIR_ID", nullable = false) @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) @Fetch(FetchMode.JOIN) private final Collection<LocalAccountPersonAttributeImpl> attributes = new ArrayList<LocalAccountPersonAttributeImpl>(0); @SuppressWarnings("unused") private LocalAccountPersonImpl() { this.id = -1; this.entityVersion = -1; this.name = null; } public LocalAccountPersonImpl(String name) { Assert.notNull(name); this.id = -1; this.entityVersion = -1; this.name = name; } public LocalAccountPersonImpl(String name, Long Id) { Assert.notNull(name); Assert.notNull(Id); this.id = Id; this.entityVersion = -1; this.name = name; } @Override public long getId() { return id; } /* (non-Javadoc) * @see org.apereo.portal.persondir.jpa.ILocalAccountPersonAttribute#getName() */ @Override public String getName() { return name; } /* (non-Javadoc) * @see org.apereo.portal.persondir.jpa.ILocalAccountPersonAttribute#getPassword() */ @Override public String getPassword() { return password; } /* (non-Javadoc) * @see org.apereo.portal.persondir.jpa.ILocalAccountPersonAttribute#setPassword(java.lang.String) */ @Override public void setPassword(String password) { this.password = password; } /* (non-Javadoc) * @see org.apereo.portal.persondir.jpa.ILocalAccountPersonAttribute#getLastPasswordChange() */ @Override public Date getLastPasswordChange() { return lastPasswordChange; } /* (non-Javadoc) * @see org.apereo.portal.persondir.jpa.ILocalAccountPersonAttribute#setLastPasswordChange(java.util.Date) */ @Override public void setLastPasswordChange(Date lastPasswordChange) { this.lastPasswordChange = lastPasswordChange; } /* (non-Javadoc) * @see org.apereo.portal.persondir.jpa.ILocalAccountPersonAttribute#getAttributeValue(java.lang.String) */ @Override public Object getAttributeValue(String name) { final List<Object> values = this.getAttributeValues(name); if (values != null && values.size() > 0) { return values.get(0); } return null; } /* (non-Javadoc) * @see org.apereo.portal.persondir.jpa.ILocalAccountPersonAttribute#getAttributeValues(java.lang.String) */ @Override public List<Object> getAttributeValues(String name) { if (name == null) { throw new IllegalArgumentException("name cannot be null"); } for (LocalAccountPersonAttributeImpl attribute : attributes) { if (name.equals(attribute.getName())) { return this.getObjectValues(attribute); } } return null; } /* (non-Javadoc) * @see org.apereo.portal.persondir.jpa.ILocalAccountPersonAttribute#getAttributes() */ @Override public Map<String, List<Object>> getAttributes() { final Map<String, List<Object>> attributeMap = new LinkedHashMap<String, List<Object>>(); for (final LocalAccountPersonAttributeImpl attribute : attributes) { final List<Object> objValues = this.getObjectValues(attribute); attributeMap.put(attribute.getName(), objValues); } return Collections.unmodifiableMap(attributeMap); } @Override public void setAttribute(String name, String... values) { this.setAttribute(name, Arrays.asList(values)); } /* (non-Javadoc) * @see org.apereo.portal.persondir.jpa.ILocalAccountPersonAttribute#setAttribute(java.lang.String, java.util.List) */ @Override public void setAttribute(String name, List<String> values) { for (LocalAccountPersonAttributeImpl attribute : attributes) { if (name.equals(attribute.getName())) { attribute.setValues(values); return; } } attributes.add(new LocalAccountPersonAttributeImpl(name, values)); } public void setAttribute(String name, String value) { for (LocalAccountPersonAttributeImpl attribute : attributes) { if (name.equals(attribute.getName())) { attribute.setValues(Collections.singletonList(value)); return; } } attributes.add(new LocalAccountPersonAttributeImpl(name, Collections.singletonList(value))); } @Override public boolean removeAttribute(String name) { for (final Iterator<LocalAccountPersonAttributeImpl> itr = attributes.iterator(); itr.hasNext(); ) { if (itr.next().getName().equals(name)) { itr.remove(); return true; } } return false; } /* (non-Javadoc) * @see org.apereo.portal.persondir.jpa.ILocalAccountPersonAttribute#setAttributes(java.util.Map) */ @Override public void setAttributes(Map<String, List<String>> attributes) { //Tries to modify as many of the existing attributes in place to reduce DB churn in hibernate //Make a local copy so we don't edit the original reference attributes = new LinkedHashMap<String, List<String>>(attributes); for (final Iterator<LocalAccountPersonAttributeImpl> attributesItr = this.attributes.iterator(); attributesItr.hasNext(); ) { final LocalAccountPersonAttributeImpl attribute = attributesItr.next(); //Remove the new values for the attribute from the input map final String name = attribute.getName(); final List<String> newValues = attributes.remove(name); //If no new values remove the attribute if (newValues == null) { attributesItr.remove(); } //Otherwise update the existing values else { attribute.setValues(new ArrayList<String>(newValues)); } } //Add any remaining new attributes to the list for (final Map.Entry<String, List<String>> attribute : attributes.entrySet()) { final String name = attribute.getKey(); final List<String> values = attribute.getValue(); this.attributes.add(new LocalAccountPersonAttributeImpl(name, values)); } } protected List<Object> getObjectValues(LocalAccountPersonAttributeImpl attribute) { final List<String> values = attribute.getValues(); final List<Object> objValues = new ArrayList<Object>(values.size()); objValues.addAll(values); return Collections.unmodifiableList(objValues); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((attributes == null) ? 0 : attributes.hashCode()); result = prime * result + ((lastPasswordChange == null) ? 0 : lastPasswordChange.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((password == null) ? 0 : password.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof LocalAccountPersonImpl)) { return false; } LocalAccountPersonImpl other = (LocalAccountPersonImpl) obj; if (attributes == null) { if (other.attributes != null) { return false; } } else if (!attributes.equals(other.attributes)) { return false; } if (lastPasswordChange == null) { if (other.lastPasswordChange != null) { return false; } } else if (!lastPasswordChange.equals(other.lastPasswordChange)) { return false; } if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } if (password == null) { if (other.password != null) { return false; } } else if (!password.equals(other.password)) { return false; } return true; } @Override public String toString() { return "LocalAccountPersonImpl [id=" + this.id + ", entityVersion=" + this.entityVersion + ", name=" + this.name + ", lastPasswordChange=" + this.lastPasswordChange + "]"; } }