3

I am working on design of my JSF web app. I dont want to have business logic code inside my Beans classes. So I decided to use DAO pattern. Right now Beans data (repairs data) is stored in xml files. Now I want to extend it for database and use Hibernate.

But I am stuck with what should I put (if anything) inside my Service class.

If I have this DAO

public interface IRepairDao {

public Repairs fetchRepairs() throws RepairDaoException;
public Manufacturers fetchManufacturers() throws RepairDaoException;
public List<Model> fetchManufacturerModels(Manufacturer manufacturer) throws RepairDaoException;
public void saveRepairs(Repairs repairs) throws RepairDaoException;
}

And for example this DAO implementation

public class RepairXmlDao implements IRepairDao {

private Serializer xmlSer;
private final String repairsXmlPath = "E:\\WORK\\Mariusz\\repairs.xml";
private final String setupXmlPath = "E:\\WORK\\Mariusz\\setup.xml";

@Override
public Repairs fetchRepairs() throws RepairDaoException {
    try {
        xmlSer = new Persister();
        InputStream fis = new FileInputStream(repairsXmlPath);
        BufferedReader in = new BufferedReader(
                new InputStreamReader(fis, Charset.forName("UTF-8")));
        String str = "", s;
        while((s = in.readLine()) != null)
            str += s;
        Repairs repairs = xmlSer.read(Repairs.class, str);
        return repairs;
    } catch(Exception e) {
        throw new RepairDaoXmlExcpetion("Thrown when fetching repairs from xml", e);
    }
}

@Override
public Manufacturers fetchManufacturers() throws RepairDaoException {
    try {
    xmlSer = new Persister();
    InputStream fis = new FileInputStream(setupXmlPath);
    BufferedReader in = new BufferedReader(
            new InputStreamReader(fis, Charset.forName("UTF-8")));
    String str = "", s;
    while((s = in.readLine()) != null)
        str += s;
    Manufacturers manufacturers = xmlSer.read(Manufacturers.class, str);
    //models = manufacturers.getManufacturers().get(0).getModels();
    return manufacturers;
    } catch(Exception e) {
        throw new RepairDaoXmlExcpetion("Thrown when fetching manufacturers from xml", e);
    }
}

@Override
public List<Model> fetchManufacturerModels(Manufacturer manufacturer) throws RepairDaoException {
    List<Model> models = new ArrayList<>();
    Manufacturers manufacturers = fetchManufacturers();
    for(Manufacturer m : manufacturers.getManufacturers()) {
        if(m.getName().equals(manufacturer.getName())) {
            models = m.getModels();
            break;
        }
    }
    return models;
}

@Override
public void saveRepairs(Repairs repairs) throws RepairDaoException {
    try {
        xmlSer = new Persister();
        File result = new File(repairsXmlPath);
        xmlSer.write(repairs, result);
    } catch(Exception e) {
        throw new RepairDaoXmlExcpetion("Thrown when saving repairs to xml", e);
    }
}

}

And what is my real benefit of adding this Service to it ?

public class RepairService {

private IRepairDao repairDao;

public Repairs fetchRepairs() throws RepairDaoException {
    return repairDao.fetchRepairs();
}

public Manufacturers fetchManufacturers() throws RepairDaoException {
    return repairDao.fetchManufacturers();
}

public List<Model> fetchManufacturerModels(Manufacturer manufacturer) 
        throws RepairDaoException {
    return repairDao.fetchManufacturerModels(manufacturer);
}

public void saveRepairs(Repairs repairs) throws RepairDaoException {
    repairDao.saveRepairs(repairs);
}
}

I cannot see any true benefits for me. Although I do see disadventages, for example if I will need to modify my DAO, I will also have to modify my Service. Or maybe my service code is wrong, and it lacks some important pieces ? Thanks for any tips or suggestions.

EDIT

Are You suggesting to create Service hierarchy, similar way to my DAO design?

public abstract class ARepairService {

protected IRepairDao repairDao;

public ARepairService(IRepairDao repairDao) {
    this.repairDao = repairDao;
}

public abstract Repairs fetchRepairs() throws RepairDaoException;

public abstract Manufacturers fetchManufacturers() throws RepairDaoException;

public abstract List<Model> fetchManufacturerModels(Manufacturer manufacturer) 
        throws RepairDaoException;

public abstract void saveRepairs(Repairs repairs) throws RepairDaoException;
}

And this implementation for example

public class RepairServiceXml extends ARepairService {

public RepairServiceXml(IRepairDao repairDao) {
    super(repairDao);
}

@Override
public Repairs fetchRepairs() throws RepairDaoException {
    return repairDao.fetchRepairs();
}

@Override
public Manufacturers fetchManufacturers() throws RepairDaoException {
    return repairDao.fetchManufacturers();
}

@Override
public List<Model> fetchManufacturerModels(Manufacturer manufacturer) 
        throws RepairDaoException {
    return repairDao.fetchManufacturerModels(manufacturer);
}

@Override
public void saveRepairs(Repairs repairs) throws RepairDaoException {
    repairDao.saveRepairs(repairs);
}
}
10101101
  • 193
  • 1
  • 13
  • 1
    I tend to use Service classes to encapsulate business logic that changes state of the domain model. The service is usually used to start/end a database or write transaction. I would not use a service like you are, which seems to be a simple path though to your DAO. I would allow your MVC layer access the DAO directly for reads and then use the service for writes. BTW, the Service should also be where new domain objects are created, so the saveRepairs() method could be createRepairOrder() and it would receive all the information needed to create a report and then save it to your DAO. – hooknc Feb 26 '20 at 17:37
  • @hooknc Are You suggesting something like in my edited version ? – 10101101 Feb 26 '20 at 19:22
  • https://stackoverflow.com/questions/30639785/jsf-controller-service-and-dao – Kukeltje Mar 07 '20 at 08:35

1 Answers1

2

A service is usually when you're bundling together your DAOs to form some business logic. Let's say you have something like this:

public interface CarService {
  public void repairCar(Car car);
}

In the implementation, you'd have to retrieve the repaired parts from the ManufacturerDao, update the car status and eventually bill the car's owner. e.g.

// skipped non-relevant parts(e.g. DAO injection) for brevity
public class CarServiceImpl implements CarService {

public ManufacturerDao manufacturerDao;
public BillingDao billingDao;
public CarDao carDao;

public void repairCar(Car car) {
    // get the car part
    Model model = car.getMissingPart();
    CarPart carPart = manufacturerDao.getNewCarPart(model);
    // install it and save the car
    car.installCarPart(carPart);
    car.setStatus(Status.REPAIRED);
    carDao.updateCar(car);
    // bill the owner
    billingDao.bill(car.getOwner());
}

}

The whole repairCar would have to be one transaction. Imagine if you're fixing the car and just when you want to bill the client, you get an exception! If the whole thing wasn't in a transaction, you'd have to pay your suppliers for the fixed car parts but ... you couldn't bill the customer. Both the business logic and the database status are broken without a transaction.

This is probably why you can't see the value of adding a service layer on top of the DAO layer. Your business logic is so easy that your service layer would be just delegating the calls to the DAO layer. For your use case, you can live without service layer until you need it. In the real world tho, business logic will not be as trivial and the service layer is a must-have.

Silviu Burcea
  • 5,103
  • 1
  • 29
  • 43
  • Yes, so indeed right now I dont need Service layer. But still appreciate your explanation, now I understand it more, and see some benefits it gives, especially in more complex logic than mine. I suppose it reducates coupling and increases encapsulation, rather than have whole complex logic in DAO layer. Thanks! – 10101101 Feb 27 '20 at 00:09
  • Yep, DAO layer should only be used for easy reads/writes. No business logic there. – Silviu Burcea Feb 27 '20 at 06:04