I am trying to migrate a Seam 2 app to CDI and use PicketLink for security. After all the reading and researching, it seems like all the examples are having one to one mapping between PicketLink model and the backend entity. e.g. Account to AccountEntity, Partition to PartitionEntity. Since I already have entities in place representing identity model, I am stuck on trying to map them to PicketLink. Here is what I have:
@MappedSuperClass
public class ModelEntityBase implement Serializable {
@Id @Generated
Long id;
Date creationDate;
}
@Entity
public Account extends ModelEntityBase {
String username;
String passwordHash;
@OneToOne(mappedBy = "account")
Person person;
}
@Entity
public Person extends ModelEntityBase {
String name;
String email;
@OneToOne
@JoinColumn(name = "account_id")
Account account;
}
Two entities (plus a super class) representing a single identity model in PicketLink, e.g. stereo type User.
Based on this why IdentityType id is String not Long, I tried to add a new Entity in:
@Entity
@IdentityManaged(BaseIdentityType.class);
public class IdentityTypeEntity implement Serializble {
@Id @Identifier
private String id;
@OneToOne(optional = false, mappedBy = "identityType")
@OwnerReference
private Account account;
@IdentityClass
private String typeName;
@ManyToOne @OwnerReference
private PartitionEntity partition;
}
I've tried a few different ways with the annotation and model classes. But when using IdentityManager.add(myUserModel), I just can't get it to populate all the entities. Is this even possible?
Got help from Pedro (PicketLink Dev). Post the answer here to help others. This is the model class I ended up using.
@IdentityStereotype(USER)
public class User extends AbstractAttributedType implements Account {
@AttributeProperty
private Account accountEntity;
@AttributeProperty
@StereotypeProperty(IDENTITY_USER_NAME)
@Unique
private String username;
@AttributeProperty
private boolean enabled;
@AttributeProperty
private Date createdDate;
@AttributeProperty
private Date expiryDate;
@AttributeProperty
private Partition partition;
// getter and setter omitted
}
And created a new entity to map to this model:
public class IdentityTypeEntity implements Serializable {
@Id
@Identifier
private String id;
@OneToOne(optional = false, mappedBy = "identityType",
cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@AttributeValue
// @NotNull
private HAccount accountEntity;
@IdentityClass
private String typeName;
@ManyToOne
@OwnerReference
private PartitionEntity partition;
@AttributeValue
private String username;
@AttributeValue
// @Transient
private boolean enabled;
@AttributeValue
private Date createdDate;
@AttributeValue
private Date expiryDate;
}
PL can map property with @AttributeProperty to entity property with @AttributeValue. But it can only map to one entity. Therefore there is no way to map, say User and its properties over to Account and Person. But you can have the entity (in my case accountEntity) in the model. I also have to duplicate a few fields in the new IdentityTypeEntity and my existing Account entity (username, eanbled, createdDate) because PL requires these. Use a @PrePersist and similar to sync them.