using a Singleton to pass credentials in a multi-tenant application a code smell? - unit-testing

I'm currently working on a multi-tenant application that employs Shared DB/Shared Schema approach. IOW, we enforce tenant data segregation by defining a TenantID column on all tables. By convention, all SQL reads/writes must include a Where TenantID = '?' clause. Not an ideal solution, but hindsight is 20/20.
Anyway, since virtually every page/workflow in our app must display tenant specific data, I made the (poor) decision at the project's outset to employ a Singleton to encapsulate the current user credentials (i.e. TenantID and UserID). My thinking at the time was that I didn't want to add a TenantID parameter to each and every method signature in my Data layer.
Here's what the basic pseudo-code looks like:
public class UserIdentity
{
public UserIdentity(int tenantID, int userID)
{
TenantID = tenantID;
UserID = userID;
}
public int TenantID { get; private set; }
public int UserID { get; private set; }
}
public class AuthenticationModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.AuthenticateRequest +=
new EventHandler(context_AuthenticateRequest);
}
private void context_AuthenticateRequest(object sender, EventArgs e)
{
var userIdentity = _authenticationService.AuthenticateUser(sender);
if (userIdentity == null)
{
//authentication failed, so redirect to login page, etc
}
else
{
//put the userIdentity into the HttpContext object so that
//its only valid for the lifetime of a single request
HttpContext.Current.Items["UserIdentity"] = userIdentity;
}
}
}
public static class CurrentUser
{
public static UserIdentity Instance
{
get { return HttpContext.Current.Items["UserIdentity"]; }
}
}
public class WidgetRepository: IWidgetRepository{
public IEnumerable<Widget> ListWidgets(){
var tenantId = CurrentUser.Instance.TenantID;
//call sproc with tenantId parameter
}
}
As you can see, there are several code smells here. This is a singleton, so it's already not unit test friendly. On top of that you have a very tight-coupling between CurrentUser and the HttpContext object. By extension, this also means that I have a reference to System.Web in my Data layer (shudder).
I want to pay down some technical debt this sprint by getting rid of this singleton for the reasons mentioned above. I have a few thoughts on what a better implementation might be, but if anyone has any guidance or lessons learned they could share, I would be much obliged.

CurrentUser isn't quite a singleton. I'm not exactly sure what you'd call it. (A singleton by definition can only exist one at a time, and any number of UserIdentity instances can be created at will by outside code and coexist without any issues.)
Personally, i'd take CurrentUser.Instance and either move it to UserIdentity.CurrentUser, or put it together with whatever similar "get the global instance" methods and properties you have. Gets rid of the CurrentUser class, at least. While you're at it, make the property settable at the same place -- it's already settable, just in an way that (1) would look like magic if the two classes weren't shown right next to each other, and (2) makes changing how the current user identity is set later harder.
Doesn't get rid of the global, but you're not really gonna get around that without passing the UserIdentity to every function that needs it.

Related

Extending SimpleNeo4jRepository in SDN 6

In SDN+OGM I used the following method to extend the base repository with additional functionality, specifically I want a way to find or create entities of different types (labels):
#NoRepositoryBean
public class MyBaseRepository<T> extends SimpleNeo4jRepository<T, String> {
private final Class<T> domainClass;
private final Session session;
public SpacBaseRepository(Class<T> domainClass, Session session) {
super(domainClass, session);
this.domainClass = domainClass;
this.session = session;
}
#Transactional
public T findOrCreateByName(String name) {
HashMap<String, String> params = new HashMap<>();
params.put("name", name);
params.put("uuid", UUID.randomUUID().toString());
// we do not use queryForObject in case of broken data with non-unique names
return this.session.query(
domainClass,
String.format("MERGE (x:%s {name:$name}) " +
"ON CREATE SET x.creationDate = timestamp(), x.uuid = $uuid " +
"RETURN x", domainClass.getSimpleName()),
params
).iterator().next();
}
}
This makes it so that I can simply add findOrCreateByName to any of my repository interfaces without the need to duplicate a query annotation.
I know that SDN 6 supports the automatic creation of a UUID very nicely through #GeneratedValue(UUIDStringGenerator.class) but I also want to add the creation date in a generic way. The method above allows to do that in OGM but in SDN the API changed and I am a bit lost.
Well, sometimes it helps to write down things. I figured out that the API did not change that much. Basically the Session is replaced with Neo4jOperations and the Class is replaced with Neo4jEntityInformation.
But even more important is that SDN 6 has #CreatedDate which makes my entire custom code redundant.

ServiceStack: Routes.AddFromAssembly still uses /json/reply path and no URL-niceness for properties

I have a ServiceStack self-hosted webservice, using the AppSelfHostBase.
WHen the Configure method is executed, I have this:
public override void Configure(Container container)
{
Config.RouteNamingConventions = new List<RouteNamingConventionDelegate> {
RouteNamingConvention.WithRequestDtoName,
RouteNamingConvention.WithMatchingAttributes,
RouteNamingConvention.WithMatchingPropertyNames,
};
Routes.AddFromAssembly(typeof(ServiceStackHost).Assembly);
and I expected the following service to be executed under /StartBankIdAuthentication path, but it resides under /json/reply/StartBankIdAuthentication instead.
public class StartBankIdAuthentication : IReturn<StartBankIdAuthenticationResponse>
{
public string IdNbr { get; set; }
}
Also, is there an automatic way to make the properties in the DTO to be under "sub-paths", like /StartBankIdAuthentication/1234 instead of the /StartBankIdAuthentication?IdNbr=1234?
I know I can manually add the Route attribute, but it seems cumbersome and also messy in many ways (not Typed, error-prone etc).
I expected the following service to be executed under /StartBankIdAuthentication path, but it resides under /json/reply/StartBankIdAuthentication instead.
The /json/reply/StartBankIdAuthentication is a pre-defined route that's always available by default, they have no relation to Auto Generated Routes.
The default Route generation strategies you've listed are already registered by default and are what's applied when you use Routes.AddFromAssembly(). You should only override with route strategies you want in addition to the defaults, and you should use SetConfig() for any configuration in ServiceStack, e.g:
SetConfig(new HostConfig {
RouteNamingConventions = { MyCustomRouteStrategy }
});
The implementation for the different Route Strategies available in ServiceStack are in RouteNamingConvention.cs, you'll need to register your own strategy for anything additional Route strategies you want.
By default additional routes are generated for any Id or IDs property, the routing docs shows examples of how they can be customized:
The existing rules can be further customized by modifying the related static properties, e.g:
RouteNamingConvention.PropertyNamesToMatch.Add("UniqueId");
RouteNamingConvention.AttributeNamesToMatch.Add("DefaultIdAttribute");
Which will make these request DTOs:
class MyRequest1
{
public UniqueId { get; set;}
}
class MyRequest2
{
[DefaultId]
public CustomId { get; set;}
}
Generate the following routes:
/myrequest1
/myrequest1/{UniqueId}
/myrequest2
/myrequest2/{CustomId}
I know I can manually add the Route attribute, but it seems cumbersome and also messy in many ways (not Typed, error-prone etc).
If you really want you can use nameof() for Typed Routes:
[Route("/" + nameof(StartBankAuthentication) +"/"+ nameof(StartBankAuthentication.IdNbr))]
I'm not sure if Mythz will maybe come up with a different of better solution, but I managed to achieve what I wanted by overriding the GetRouteAttributes, and by using reflection, I could create what I wanted. It looks like this:
public override RouteAttribute[] GetRouteAttributes(Type requestType)
{
string fullname = requestType.FullName.Replace("AlfaOnlineServiceModel.Api.", "");
string path = "/" + fullname.ToLower().Replace(".", "/");
RouteAttribute[] routes = base.GetRouteAttributes(requestType);
if (routes.Length == 0)
{
routes = new RouteAttribute[1];
PropertyInfo[] pInfos = requestType.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly);
foreach(PropertyInfo pi in pInfos)
{
path += "/{" + pi.Name + "}";
}
routes[0] = new RouteAttribute(path);
}
return routes;
}
Which will give for example:
MyMethodResult
The following routes are available for this service:
All Verbs /myCoolPath/mySubPath/myMethod/{MyProperty}

Plugin re-using Target parameter between calls

I've created and deployed a plugin for the Update event of a custom entity but it seems when multiple users update different entities within quick succession the plugin uses the first entity it receives for each call.
To investigate further I added NLog via NuGet and at the beginning of the Execute function I generate a Guid and log the entity Id and the Guid. When I look in the log I can see the same ID and Guid logged 3-4 times before both change.
What I think is happening is the code is being run for each user but using the first entities details, applying only to the first entity.
Why is this happening and how can I stop it? The problem is users are saying the plugin is erratic.
Here is my code:
public class OnUpdateClaimSection : IPlugin
{
private static Logger logger = LogManager.GetCurrentClassLogger();
private string logId = Guid.NewGuid().ToString();
public void Execute(IServiceProvider serviceProvider)
{
try
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
logger.Debug("{0} {1}|{2}|{3}", logId, context.MessageName, context.PrimaryEntityName, Common.GetSystemUserFullName(service, context.UserId));
var entity = context.InputParameters["Target"] as Entity;
logger.Debug("{0} {1}", logId, entity.Id);
var claimSection = GetClaimSection(service, entity.ToEntity<ClaimSection>());
CalculateClaimTotals(service, claimSection);
}
}
catch (Exception ex)
{
logger.Error("{0} Exception : {1}", logId, ex.Message);
throw;
}
}
}
Plugin classes are instantiated once by the CRM platform and are then reused for requests. Therefore you must be very careful when using class field variables, because they are not guaranteed to be thread-safe.
In your example field logId is modified in the Execute method. Race conditions of multiple threads are causing the effects you describe.
I suggest to only use plugin class fields when you have made sure that their implementation is absolutely thread-safe.

JPA - How to avoid getting an empty list?

I'm creating a sort of a social networking site, like Facebook, as a university project. Users can upload photos, but I'm somehow unable to retrieve the list of photos for a particular user.
Here's how I'm doing it right now:
#Entity
#Table(name = "users")
public class User implements Serializable {
#Id
private String emailAddress;
private String password;
private String firstName;
private String lastName;
(...)
#OneToMany(mappedBy = "owner", fetch = FetchType.EAGER)
private List<Photo> photos;
public User() {
}
(...)
public void addPhoto( Photo photo){
photos.add(photo);
}
public List<Photo> getPhotos() {
return photos;
}
}
And here's the Photo entity:
#Entity
public class Photo implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String url;
private String label;
#ManyToOne
private User owner;
public Photo() {
}
(...)
public User getOwner() {
return owner;
}
}
Each photo is uploaded by creating a post that contains it. Here's the EJB that does it:
#Stateless
public class PublicPost implements PublicPostRemote {
#PersistenceContext
EntityManager em;
#Override
public void createPost(LoginUserRemote loginUserBean, String targetEmail, final String content, final String photoURL) {
if (loginUserBean.isLoggedIn()) {
final User author = loginUserBean.getLoggedUser();
System.out.println(targetEmail);
final User target = em.find(User.class, targetEmail);
if (author != null && target != null) {
//See if there's a photo to post as well
Photo photo = null;
if (photoURL != null) {
photo = new Photo(photoURL, author, content);
em.persist(photo);
}
MessageBoard publicMessageBoard = target.getPublicMessageBoard();
Post post = new Post(author, content);
post.setMessageBoard(publicMessageBoard);
if (photo != null) {
post.setPostPhoto(photo);
}
em.persist(post);
em.refresh(publicMessageBoard);
//Send an e-mail to the target (if the author and the target are different)
if (!author.getEmailAddress().equals(target.getEmailAddress())) {
final String subject = "[PhaseBook] " + author.getEmailAddress() + " has posted on your public message board.";
Thread mailThread = new Thread() {
#Override
public void run() {
try {
GMailSender.sendMessage(target.getEmailAddress(), subject, content);
} catch (MessagingException ex) {
Logger.getLogger(PublicPost.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
mailThread.start();
}
}
}
}
}
So what happens is: I create a new post that contains a photo, yet later, when I use this, on the web tier...
LoginUserRemote lur = (LoginUserRemote)session.getAttribute("loginUserBean");
User user = lur.getLoggedUser();
List<Photo> photos = user.getPhotos();
System.out.println();
System.out.println("This user has this many photos: " + photos.size());
...it always tells me that the user has 0 photos. Why is this? Am I defining the relationship between user and photo incorrectly? Am I forgetting to persist/refresh anything? Or does the problem lie somewhere else?
If you store a detached User object (the logged in user) in the HTTP session, and then create and persists photos having this detached user as owner, JPA won't automatically add the photo to the detached user. For the entity manager, this detached user doesn't exist: it's not under its responsibility anymore.
Even if User was still attached, it's your responsibility to maintain the coherence of the object graph. If you modify one side of the association (by setting the user as owner of the photo), you should also modify the other side (by adding the photo to the list of photos of the owner).
I'm not absolutely sure this is the cause of the problem, because you haven't shown us what the loginUserBean was and did to get the logged in user, but it might be the answer.
There is a series of issues here:
Are photos actually stored in the database? Maybe you don't have a transaction open?
You are not updating both sides of the association.
Theoretically you only need to update the owning side, but better be safe than sorry:
photo = new Photo(photoURL, author, content);
em.persist(photo);
author.addPhoto(photo);
You are fetching the user from a session and then retrieving associated collection of photos. Do you really know what this means? If the user has hundreds of photos, do you really want to store them in HTTP session along with the user all the time? This is not how Facebook works ;-).
I think refreshing your entity (with em.refresh(lur.getLoggedUser())) might work, but only at university, not in real life. Loading all the user photos at once into memory is an overkill. Personally I would even remove photos association from user to avoid this. Load one page at a time and only on demand.
Even if you know what you are doing or such a behaviour is acceptable, objects stored in HTTP session are so called detached from persistence context, meaning your persistence provider does no longer keep track of them. So adding a photo does not mean that the photos collection will be magically updated in every object. I think about carefully, this would be even worse.
Last but not least, your createPost() really needs some code review. It does at least 4 things at once, System.out, one time threads created on demand, silently doing nothing when preconditions are not met (like user not being logged in, missing parameters), mixing concerns on different level of abstraction. Don't want to be too meticulous, but your grade might be influenced by the quality of code.

What's the lazy strategy and how does it work?

I have a problem. I'm learning JPA. I'm using embedded OpenEJB container in unit tests, but only working is #OneToMany(fetch=EAGER). Otherwise is the collection allways null. I haven't found, how the lazy strategy works, how the container fills the data and in which circumstances triggers the container the loading action?
I have read, that the action triggers when the getter is being called. But when I have the code:
#OneToMany(fetch = LAZY, mappedBy="someField")
private Set<AnotherEntities> entities = new Set<AnotherEntities>();
...
public Set<AnotherEntities> getEntities() {
return entities;
}
I'm always getting null. I thing, the LAZY strategy cannot be tested with embedded container. The problem might be also in the bidirectional relation.
Does have anybody else similar expiriences with the JPA testing?
Attachments
The real test case with setup:
#RunWith(UnitilsJUnit4TestClassRunner.class)
#DataSet("dataSource.xml")
public class UnitilsCheck extends UnitilsJUnit4 {
private Persister prs;
public UnitilsCheck() {
Throwable err = null;
try {
Class.forName("org.hsqldb.jdbcDriver").newInstance();
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
props.put("ds", "new://Resource?type=DataSource");
props.put("ds.JdbcDriver", "org.hsqldb.jdbcDriver");
props.put("ds.JdbcUrl", "jdbc:hsqldb:mem:PhoneBookDB");
props.put("ds.UserName", "sa");
props.put("ds.Password", "");
props.put("ds.JtaManaged", "true");
Context context = new InitialContext(props);
prs = (Persister) context.lookup("PersisterImplRemote");
}
catch (Throwable e) {
e.printStackTrace();
err = e;
}
TestCase.assertNull(err);
}
#Test
public void obtainNickNamesLazily() {
TestCase.assertNotNull(prs);
PersistableObject po = prs.findByPrimaryKey("Ferenc");
TestCase.assertNotNull(po);
Collection<NickNames> nicks = po.getNickNames();
TestCase.assertNotNull(nicks);
TestCase.assertEquals("[Nick name: Kutyafája, belongs to Ferenc]", nicks.toString());
}
}
The bean Presister is the bean mediating access to the entity beans. The crucial code of class follows:
#PersistenceUnit(unitName="PhonePU")
protected EntityManagerFactory emf;
public PhoneBook findByPrimaryKey(String name) {
EntityManager em = emf.createEntityManager();
PhoneBook phonebook = (PhoneBook)em.find(PhoneBook.class, name);
em.close();
return phonebook;
}
Entity PhoneBook is one line of phone book (also person). One person can have zero or more nick names. With EAGER strategy it works. With LAZY the collection is allways null. May be the problem is in the detaching of objects. (See OpenEJB - JPA Concepts, part Caches and detaching.) But in the manual is written, that the collection can be sometimes (more like manytimes) empty, but not null.
The problem is in the life cycle of an entity. (Geronimo uses OpenJPA, so le't see OpenJPA tutorial, part Entity Lifecycle Management.) The application uses container managed transactions. Each method call on the bean Persiser runs in an own transation. And the persistency context depends on the transaction. The entity is disconnected from its context at the end of the transaction, thus at the end of the method. I tried to get the entity and on second line in the same method to get the collection of nick names and it worked. So the problem was identifyed: I cannot get additionally any entity data from the data store without re-attaching the entity to some persistency context. The entity is re-attached by the EntityManager.merge() method.
The code needs more correctures. Because the entity cannot obtain the EntityManager reference and re-attach itself, the method returning nick names must be moved to the Persister class. (The comment Heureka marks the critical line re-attaching the entity.)
public Collection<NickNames> getNickNamesFor(PhoneBook pb) {
//emf is an EntityManagerFactory reference
EntityManager em = emf.createEntityManager();
PhoneBook pb = em.merge(pb); //Heureka!
Collection<NickNames> nicks = pb.getNickNames();
em.close();
return nicks;
}
The collection is then obtained in this way:
//I have a PhoneBook instance pb
//pb.getNickNames() returns null only
//I have a Persister instance pe
nicks = pe.getNickNames(pb);
That's all.
You can have a look at my second question concerning this topic I'have asked on this forum. It is the qustion OpenJPA - lazy fetching does not work.
How I would write the code
#Entity
public class MyEntity {
#OneToMany(fetch = LAZY, mappedBy="someField")
private Set<AnotherEntities> entities;
// Constructor for JPA
// Fields aren't initalized here so that each em.load
// won't create unnecessary objects
private MyEntity() {}
// Factory method for the rest
// Have field initialization with default values here
public static MyEntity create() {
MyEntity e = new MyEntity();
e.entities = new Set<AnotherEntities>();
return e;
}
public Set<AnotherEntities> getEntities() {
return entities;
}
}
Idea no 2:
I just thought that the order of operations in EAGER and LAZY fetching may differ i.e. EAGER fetching may
Declare field entities
Fetch value for entities (I'd assume null)
Set value of entities to new Set<T>()
while LAZY may
Declare field `entities
set value of entities to new Set<T>()
Fetch value for entities (I'd assume null)'
Have to find a citation for this as well.
Idea no 1: (Not the right answer)
What if you'd annotate the getter instead of the field? This should instruct JPA to use getters and setters instead of field access.
In the Java Persistence API, an entity can have field-based or
property-based access. In field-based access, the persistence provider
accesses the state of the entity directly through its instance
variables. In property-based access, the persistence provider uses
JavaBeans-style get/set accessor methods to access the entity's
persistent properties.
From The Java Persistence API - A Simpler Programming Model for Entity Persistence