• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

code suggestions?

 
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Can you give me some suggestions on how to improve the following classes? The getConnection method seems like something that I can abstract out, but then I would need to refactor the classes to be Singletons?



 
Marshal
Posts: 28177
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'd say that having a Database object which encapsulates a BasicDataSource object looks like the way to go to me. When you do that then as you say, you can raise the getConnection() method into the Database class. The static initializers you have in your subclasses then become either instance initializers or code within the constructors of those subclasses. And the only static method you need once you've done that is the close() method that you already have in the Database class. (By the way you don't need the overridden method at line 40 because a PreparedStatement already is a Statement.)

As for making a Database object a singleton: unless there's a firm rule that you absolutely can't instantiate more than one BasicDataSource per database in your code, or else bad things will happen, I wouldn't do that. My guess is that creating two BasicDataSource objects wouldn't cause any problems, so it isn't worth trying to write the singleton logic. Just write your code to create only one Database object per database.
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Is this what you were suggesting? What would be the best way to only create 1 database object per database? I can see the advantages of this class, but I wasn't sure how to only create 1 instance.


 
Paul Clapham
Marshal
Posts: 28177
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes, I think that's about it. You asked how to create only one database object; here's the code:



Do this in your initialization code.
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hmm, I guess that would be possible in some apps, but I'm not so sure about servlets, which ours is. We use Jersey. Is a singleton the only way? It seems like we wouldn't be taking advantage of the connection pooling by instantiating the Database class in every class that needs db access.

 
Paul Clapham
Marshal
Posts: 28177
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Servlets? You're right, that's a different kettle of fish. But it seems to me that normally you would configure a connection pool (or in your case, two connection pools) in your servlet container, and then get your data source and connections from that pool, rather than building that logic into your servlets or their data layer.

At least that's what I used to do when I was working with servlets, although usually the details were taken care of by Hibernate. But here's a link to one way to do it: Database Connection Pooling in Tomcat -- you can ignore the Eclipse business and you might have to translate the instructions for something else if you aren't using Tomcat.
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Okay, So I tried to setup connection pooling using Jetty, but I'm not so sure that it is working. Here's the thread asking about it jetty question
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
hmm, just realized that I can't use the db class via the cmd line if I utilize Jetty connection pooling.

What would be the preferred way to utilize connection pooling as in a servlet as well as via cmd line? Would it be going back to my original code?
 
Paul Clapham
Marshal
Posts: 28177
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, the code you put into your servlet is going to use web-app-based mechanisms to get database connections, whereas the code you put into your command-line app isn't (unless you go to the trouble of building JNDI into your command-line app). So you can't really use the same code for both. But you could still look into the possibility of external configuration of the connection pool, and do that in your command-line app. Then the two code bases would look pretty similar, except for the getConnection() method.
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
How would you go about running a method via the cmd line from code designed to be run in a servlet?

Ex. The app is a servlet app. While developing a class, I might implement the main method and call it via the cmd line. This is to quickly "test" the class. This class queries the db (which is configured using jndi).

Is there any way to do this?
 
Paul Clapham
Marshal
Posts: 28177
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Rj Ewing wrote:How would you go about running a method via the cmd line from code designed to be run in a servlet?



I wouldn't. The servlet is designed to respond to an HTTP request, and that isn't the process that applies in a command-line application.

Of course it's recommended that you should abstract your business logic into a separate tier of classes which can be accessed by either version of the code, i.e. don't mix the controller code with the model code. Likewise accessing a connection pool from a servlet versus a command-line application is going to be a different process, again because of the infrastructure where the connection pool is running, so expecting to use the same code in both is going to be impractical unless you build a lot of infrastructure to make your command-line application look similar to a web application container.

And really there's not much code to be dealt with in your Database class. You've got a static helper method to close database objects, and you've got a method to get a connection from a connection pool, and that's about it. The former is independent of the environment, and the latter -- you could have separate servlet and command-line versions. There's no reason for the two methods to be in the same class, either.
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I really appreciate you taking the time to help me out. Sorry I'm so confused

Our business logic is abstracted out. The db is never accessed directly in the controller logic.

Ex. of normal app flow: POST request to jersey resource UserService.create(UserForm). The servlet method calls UserMinter.create(User). In UserMinter.create(User) I grab a db connection.

Now for some reason I want to create a new User via the cmd line by directly calling UserMinter.create(User) in the UserMinter.main(args[]) method.

How would I setup my Database class to handle the above?

 
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
My comments re the Database class:

1. Why declare it as abstract? If it's so that it can't be instantiated, prefer a private constructor then make the class final.

2. Having those three parameters for close() is smelly to me. You could take advantage of method overloading, self referencing, and call chaining to separate each part into its own method. It's a little more code but this is what you'll get:


I've done many things like this in my own code; haven't tried the above code though so caveat ranchor (borrowing something I saw Winston post the other day)
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
junilu,

I have the need to acces 2 dbs. I made the Database class abstract so I can extend it with my Classes to access each individual database.
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Are you referring to two different tables in the same database or two different databases altogether? If this is not schoolwork, why aren't you using something like Spring to do that kind of work? Spring takes care of a lot of the plumbing and their code is far more robust than what you could ever hope to write in any decent amount of time.
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
2 different databases altogether.

I began working on this codebase a couple of months ago. When I joined, the backend and rest interface was mostly developed, thus many of the design (or lack of) decisions were already made. My first tasks were to provide a web UI. Currently I do about 95% of the programming with this app. I would consider myself a junior developer and there is no one to do code reviews. My boss (who originally developed the app) is a better interface between the scientific community then a developer. When I began, I was new to java, only implemented new features, didn't work much with the existing code, and frankly didn't know any better. However the more I worked on the code and the more the software is being adopted and the more feature request that are being made, the I have become more frustrated with the codebase from a fragility and maintainability standpoint. Now I am learning into design patterns and how to make the more maintainable. So I am hoping to slowly refactor the codebase as well as creating unit tests.

I recently did a refactoring where I removed the common code into different modules, as when a few institutions who want slightly different functionality. The basic functionality is the same, validate a spreadsheet of data samples given a config file and upload the data, creating a persistent identifier for the dataset. Now each institution gets its own instance and we can develop the needed features without polluting the core codebase.

Now I haven't figured out the best plan of attack for refactoring to a better design. The more I read about design patterns, the more I get confused and not sure on how to determine what pattern to use. Should I continue to use jdbc or go with an orm? Would it make sense to use a framework such as spring at this point? Should I create a DAO? Should I create an object that matches each table (User, Dataset, Expedition, Project), or would that be inefficient? (ex. fetching all projects will create a bunch of Project object just to get a list of project ids and titles to populate a select box)

This is a link to the github organization. The *-fims repos are the institution specific code which depends on the biocode-fims-* repos

Anyways, I've come to coderanch to help be become a better developer and to understand when and why to do something a certain way.
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
A few books I would recommend for you:

Michael Feathers - Working Effectively With Legacy Code (The WELC book)
Joshua Kerievsky - Refactoring to Patterns

These are both excellent books to use as references when working with legacy code (code that doesn't have unit tests)

As additional references:

Robert Martin:
- Agile Software Development - Principles, Patterns, & Practices (The PPP book)
- Clean Code

Martin Fowler - Refactoring: Improving the Design of Existing Code (the original Refactoring Catalog)
Corey Haines - 4 Rules for Simple Design - great book if you want to learn about design thinking, refactoring, and test-driven development all in one book
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
With a non-trivial application, I would really start looking at incorporating Spring to handle all the nitty-gritty infrastructure level work. Spring can do a lot of the heavy lifting for you and free you up to think about more high-level concepts.

Layering is definitely important when you're restructuring your design. Separate concerns, testing along layer interfaces first. Above all, refactor in small steps and try to have tests before you refactor anything -- that's your safety net. Refactoring large sections of code all at once is very dangerous and can create more problems on top of the ones you already have.

Lastly, unless absolutely critical, don't optimize for performance just yet. Concentrate on cleaning up the code and design first. Then you can use a profiler to see where your bottlenecks are in your code. Don't optimize for performance based on gut feelings. Your digestive tract is very bad at identifying performance issues in your code. Seriously, use a profiler.

 
Paul Clapham
Marshal
Posts: 28177
95
Eclipse IDE Firefox Browser MySQL Database
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
So many questions... but I know what you mean, there are so many choices.

Let me just throw out a couple of ideas, then. As for subclassing Database so you can access more than one database, that's not really the right thing to do. You should design a subclass if you want it to do what the superclass does, only differently. In your case a Database object (if you need one at all) manages connections (or a connection) to a database. There's no need for subclasses -- just pass parameters to the constructor (or setter methods) which say which database it should connect to. Just like you don't need a subclass of java.io.File for each file you want to connect to.

Your idea of creating an object for each table: That's a good idea, and if you're going to do that you could certainly consider using an ORM because those are exactly the "Objects" in "Object-Relational Mapping" code. You might think it's "inefficient" to create a list of Project objects, but your alternative is to collect together the same data (or at least most of it) in some less organized form. It's possible to write SQL-like queries in most ORMs if you really can't get over that issue, but for most systems your computer has plenty of memory and is astonishingly fast so it isn't really an issue.

As for Spring: I was a Java programmer for 10 years and never used it, for various reasons not related to its quality or utility. I've been retired for 3 years now but I'm still a programmer, and my pet application could easily be rewritten for some other platform to keep me occupied. So I looked at Spring and recoiled because (ironically) of how comprehensive it is. I will have to leave it to others who actually use it to discuss it, but for me it was like looking out over the ocean and realizing that I didn't even have a kayak. But I'm sure if you wanted to spend some time getting into it, that might well be a good decision. Frameworks come and go but Spring seems to have survived and thrived.

But to move to Spring you would probably have to break your application into little pieces, modify them, and incorporate the result into Spring. Small modifications of your existing code over time could also produce something workable, but in either case there's a lot to learn. The advantage of Spring is that it tells you what architectural principles are useful and then implements them on your behalf.
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
And by concentrating on cleaning up the code first, I mean this:

Follow the 4 Rules of Simple Design:
1. All tests pass
2. Code is expressive and unambiguous (see the Clean Code book for tips on giving good names)
3. No duplication in code or in configuration
4. Classes, methods, interfaces are small

Try to adhere to the SOLID, DRY, GRASP design principles

Write more automated unit tests. Make your tests look like detailed design specifications. That is, they should look like simple examples of how your class APIs are to be used. The simpler you can make your test code, the simpler, better, and cleaner your production code will get.

 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Just so you know you're not alone, I have been following the strategy I just gave you for about 10 years now. The last 6 years or so have been with an application that started out as a horrific mess. I mean like I wanted to find the people who wrote that and literally choke them out. And I could do it, too, I have the skills

But with a lot of patience, perseverance, and following the strategy I gave and some of what Paul said, I was able to introduce Spring into the mix and get a handle on some of the horrific things that had been coded. This app has run relatively trouble free since I took over it and that is due in no small part to a lot of the ideas and techniques that I got from the books that I recommended to you.

HTH
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Paul Clapham wrote:
But to move to Spring you would probably have to break your application into little pieces, modify them, and incorporate the result into Spring. Small modifications of your existing code over time could also produce something workable, but in either case there's a lot to learn. The advantage of Spring is that it tells you what architectural principles are useful and then implements them on your behalf.


When I inherited the legacy app from Hell that I mentioned, it was built with Ant and did not have any unit tests at all. Pure Legacy App if there ever was one. We first switched to Maven, which was about a month's work. Then we introduced Spring. It was relatively painless to introduce Spring because we started off by using it only for new features, therefore new code. Then we started moving the data access layer over to Spring and got rid of the ridiculous home-grown database plumbing that the previous team of itinerant consultants had written. That really helped us get a handle of what the database code was doing because we were able to get rid of all the boilerplate code and leave only the essence of the data access logic. For me, this was the biggest bang we got for the buck that we spent in moving to Spring.
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The more I think about it, the more I would be inclined to move to Spring if I were maintaining that app. Spring will allow you to abstract away the fact that you're dealing with two databases. That detail would be hidden inside Spring configuration. Your Data Access layer would just be comprised of DAO implementations. I keep DAO interfaces as part of the core project. The Data Access layer module will be dependent on the Core module of the project via the DAO interfaces that it implements and the Domain Objects that it uses and returns to the Core, which is comprised of Business Services and Domain Objects. I usually follow the Hexagonal Architecture pattern for my apps.

Now, with technologies like Docker really getting a lot of adoption and microservices architectures becoming more attractive as a result, I'm finding that the hexagonal architecture makes it almost trivial to turn my application components into microservices.
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
And one more thing:

The main refactoring techniques that I used were very simple:

1. Rename methods/classes/variables/anything to clarify/reveal intent - spell out words, make sure the semantics of the names are right, make your code make sense when you read it OUT LOUD. The Clean Code book will give you all the guidelines for good names.

2. Extract to eliminate duplication (eliminate duplication in both code and configuration)

3. Composed Method - this is to have SLAP (Single Level of Abstraction Principle) - See Joshua Kerievsky's book "Refactoring to Patterns"


That's it. This takes care of at least 80% of the typical problems in your code.

Combine that with the rest of the things that I said before and you should be well on your way to a better code base.
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
wow! Thank you both for all of the great info. It's extremely helpful. I'll need to read it a couple of time to comprehend it all.

Junilu, quick question in regards to your recommendation for moving to Spring.

The 2nd database is only for storing the actual datasets. We currently are using a triple store (apache fuseki). However the 2nd mysql db is because a client didn't want to use the triple store implementation and prefered mysql for storing the datasets.

Does that make any difference in your recommendation?
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Rj Ewing wrote:
Junilu, quick question in regards to your recommendation for moving to Spring.

The 2nd database is only for storing the actual datasets. We currently are using a triple store (apache fuseki). However the 2nd mysql db is because a client didn't want to use the triple store implementation and prefered mysql for storing the datasets.

Does that make any difference in your recommendation?


Yes, it would make a difference in that I would strongly recommend moving to Spring

If I'm reading this right, this is a one-off situation where you have a client with a slightly different implementation requirement. The essence of what you're doing with the data that you get from that different implementation remains the same in the rest of your program. This is an excellent opportunity to use the abstractions that DAOs can provide. Inside your program, you deal only with the DAO interface which defines the general behavior. In the data access layer, you can switch out implementations of the DAO. This now becomes a configuration issue. Configuration is Spring's wheelhouse, so I would say that you would be helped tremendously by using Spring instead of self-managing another custom data implementation every time a customer has a specific implementation requirement like what you describe.

The principle involved here is that of stabilization and abstraction. When you have instability in your design, such as having to implement another Database class when a customer asks for a different implementation, you hide that instability from the rest of the program. You introduce a stable interface, that provides an abstraction to the functionality and makes whatever implementation is behind it irrelevant. You are then free to switch out implementations as you please without disturbing the rest of the application.
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


I think it's all starting to come together for me. After I posted that question, I started writing a proposal for integrating with spring. While you were much more detailed, I essential said the same thing in my proposal.

Thanks again for all the great information!
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It's kind of like how your modern TV set has an HDMI port for video input. You can connect virtually any kind of device to your TV via the HDMI port. BluRay player, cable TV box / DVR, a laptop, a game console, virtually anything that can support an HDMI interface. Your TV doesn't care what kind of device it's getting a video feed from, as long as it comes in a format that it can interpret properly. Spring is the multi-port receiver that sits between your different devices and your TV. You can plug in all your different devices into the receiver and with just one or few presses of a button, you can easily switch from one input device to another. Your receiver has only one output that goes to one input HDMI port on your TV but it has multiple input ports to support multiple different devices.

So HDMI is your DAO interface that defines a general capability, Spring is your receiver and container/manager for all your different databases, and your different database are all your different video-capable devices.

Does that make sense?
 
Marshal
Posts: 79151
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Discussion far too difficult for this forum: moving.
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:Above all, refactor in small steps and try to have tests before you refactor anything -- that's your safety net. Refactoring large sections of code all at once is very dangerous and can create more problems on top of the ones you already have.



Do you have any suggestions on how I would go about testing this class before refactoring? There's db calls directly alongside logic methods like login? I think I would like to create a User entity as well as a UserDAO. Then in login, I could get call UserDAO.findByUsername("user").getHashedPass(). I think that will make things much more testable as I can mock User and UserDAO. So how do I create tests before the refactor?

Also, do you have any tips to start integrating spring? Our app is currently a jersey servlet. I was thinking that I would start integrating spring with any new development and refactoring.
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Rj Ewing wrote:
Do you have any suggestions on how I would go about testing this class before refactoring? There's db calls directly alongside logic methods like login? I think I would like to create a User entity as well as a UserDAO. Then in login, I could get call UserDAO.findByUsername("user").getHashedPass(). I think that will make things much more testable as I can mock User and UserDAO. So how do I create tests before the refactor?

Also, do you have any tips to start integrating spring? Our app is currently a jersey servlet. I was thinking that I would start integrating spring with any new development and refactoring.



One of the first things I have to do when moving to Spring is to find collaborators of classes that I want Spring to manage. Then I find where the classes are creating the collaborators either with new or by calling factory methods. Those are what Michael Feathers calls "seams" - where different parts of your program come together. You have to start teasing the seams apart. This has a lot to do with the Law of Demeter and Dependency Injection so read up on that.

Once I've identified the collaborators and found the places where they're being instantiated, I replace those with references to an instance variable instead. That is, you stop creating your collaborators and start assuming that they are getting injected into your class. This loosens up coupling. When coupling is loosened like that, you can start testing using Mocks. When you use mock objects, that's where the DAO interface starts to come into play. You can mock a DAO and simulate the data being returned from a data repository.

The "smell" in that Authenticator class is that it has at least two concerns mixed in together in one class. First, it has the concern of authenticating users. The other concern is that of accessing a data repository where user information is stored. These concerns should NOT be mixed together in one class. The data access needs to be extracted and abstracted out and hidden behind a DAO interface. Once you do that, you can start testing the authentication functionality.

Spring Security gives you a good framework for doing authentication and authorization. You may have to rework your database to have tables that Spring Security requires though. But it's well worth the effort to give SS what it wants because you can relinquish a lot of the heavy work to it afterwards. You just deal with high-level interfaces to get the job of A/A for your app done and get on with the real business at hand.

Hope this helps.
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Rj Ewing wrote:Then in login, I could get call UserDAO.findByUsername("user").getHashedPass()


Again, Law of Demeter should be considered here. Basically, Tell Don't Ask. That can get a little confusing, kind of that optical illusion GIF of the train that at one glance appears to be going into a tunnel and with another blink it can appear to be coming out of the tunnel.

Anyway, what you're doing there is ASKing for the hashed password so you can do something with it. To follow the TELL approach, you would do something like this instead:

In this case, the hashed passphrase does not escape out of the data layer. You pass in the passphrase that the user entered and the user who entered it and the DAO has machinations inside that will figure out whether the passphrase matches. This is just a first step to refactoring. If you introduce Spring Security, more steps will be needed to adapt the design to fit what Spring Security expects. But again, this would be the first step.

I call this the process of "turning your brain backwards" because a lot of our tendencies in designing software run counter to good OO principles. I have seen this kind of thing over and over and it's fascinating to me. In fact, I'm going to include some discussions about this in a book on TDD that I just finally started writing.

HTH

Edit:

The confusing part about that example with regard to Tell Don't Ask is that you can still look at it as though you're ASKing whether the user has a matching password. The key here is what kind of information you're getting back.

In the case of ASKing, you are getting back information that you want to do further related processing with. You're saying "Hey, give this guys passphrase, I need it to see if he's an authentic user." When you get the stored passphrase back, you do more work that's still related to authentication.

In the case of TELLing, you're just getting the final result back so you can move on and do something else that's not directly related to authentication. You're basically TELLing somebody else, "Hey, go and figure out if this passphrase is good or not. I don't care how you do it, just tell me if it's good or not. I need to know so I can decide whether to do this other stuff or not."

The difference is "Give me this little piece of information so I can do the heavy work of figuring out" vs. "You go do the heavy work of figuring out, here's what you're going to need to do that. Tell me when you're done."

Hope that makes sense.
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Here's an article you might want to read: https://pragprog.com/articles/tell-dont-ask
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
hmm, interesting. I'll take a look at that article.

So we are gonna go ahead and start using spring. I've got a question about DI. Is the following the best way to inject the dataSource? Or just change the MySqlUploader dataSource attribute to match the specific bean (datasetDataSource), and remove the mySqlUploader bean from the applicationContext.xml

I believe I need to declare the MySqlUploader as an attribute w @Autowire whenever I want to use it, otherwise DI wouldn't work, correct?

Jersey Resource




applicationContext.xml
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Rj Ewing wrote:
I believe I need to declare the MySqlUploader as an attribute w @Autowire whenever I want to use it, otherwise DI wouldn't work, correct?


Just scanning over quickly but that looks about right.

You don't have to do this:

Doing it that way makes it necessary to change the file for every variation. You want to parameterize/tokenize that so the XML is stable. Put the value that can change in a properties file. In your config, you'd have the property name as a placeholder token that gets replaced with the value read from the properties file. You can also do that via annotations. No time right now to give you an example but you should be able to find more info with Google.
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Also, how do you handle a situation in a DAO when you need additional params that are generated during runtime, and you want the params in the constructor because the class depends on them? Ex:



Is there a way to so something like and have the dataSource still get injected?

It doesn't seem right to have an empty constructor and require the information as params for the method. Especially if there are multiple methods that require the same params.
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:
Doing it that way makes it necessary to change the file for every variation. You want to parameterize/tokenize that so the XML is stable. Put the value that can change in a properties file. In your config, you'd have the property name as a placeholder token that gets replaced with the value read from the properties file. You can also do that via annotations. No time right now to give you an example but you should be able to find more info with Google.



the commented out xml was just when I was trying to get spring to work. I wouldn't leave it in there.
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Don't do that. Once you relinquish lifecycle management of a class to Spring, it's best not to mess with calling new on it. Add a method and call that instead.
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:Don't do that. Once you relinquish lifecycle management of a class to Spring, it's best not to mess with calling new on it. Add a method and call that instead.



what's the best practice? a setter for each property, just use as params for the method when needed, or create a method just for setting multiple attributes?
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Most things that you ask Spring to manage become essentially singletons. They're not true Singletons but you can think of them as such. They will get injected into whatever things need to collaborate with them. Being "singletons", it's best for these things to not have any mutable state. You would just call methods and since parameters are generally thread-safe, it's fine that you only have the one object that you're reusing over and over again.

You would just pass in parameters to the repository method that you want to invoke. I limit parameters to 3 at most. Once I need to load up more that 3 pieces of information in the parameter list, I create another "capsule" object to hold everything. Kind of like those capsules that get vacuumed back and forth at the drive-thru window at your bank or pharmacy. This way, you make the method API more stable. Then I'd create another builder for the Capsule.

 
Oh sure, it's a tiny ad, but under the right circumstances, it gets bigger.
a bit of art, as a gift, that will fit in a stocking
https://gardener-gift.com
reply
    Bookmark Topic Watch Topic
  • New Topic