I writing application that collect job offers from few websites and tries to apply for each joboffer using implementation of this interface for each website:
public interface JobApplier { void applyForJob(JobOffer jobOffer, ProfileData profileData, String message, List<Document> cvList, PortalAccount account); }
Some websites allows applying for job directly but some just collect job offers and then when you want apply for job, you are redirected to another website for example, employer`s website and then you can apply for job.
For each website there is implementations of JobApplier.
In case of redirect to another page, FormNotSupportedException is thrown with Url to redirected page. Then, application should find proper JobApplier (using url from exception) for redirected website and try apply for this job.
ApplicationService:
@Service public class ApplicationService2 { private final ApplicationRepository applicationRepository; private final JobOfferService jobOfferService; private Map<PortalType,JobApplier> appliers; @Autowired public ApplicationService2(ApplicationRepository applicationRepository, JobOfferService jobOfferService, Map<PortalType, JobApplier> appliers) { this.applicationRepository = applicationRepository; this.jobOfferService = jobOfferService; this.appliers = appliers; } // Method will try apply for job, if succeeded it will save Application entity in DB with status SEND // if failed it will throw proper Exception and save Application entity in DB with status FAILED public void applyForJob(JobOffer jobOffer, ProfileData profileData, String message,List<Document> files ,PortalAccount account) { Application application = new Application(); application.setJobOffer(jobOffer); application.setDocuments(new ArrayList<>(files)); application.setMessage(message); application.setUser(profileData.getUser()); apply(application,profileData,account); } private void apply(Application application, ProfileData profileData,PortalAccount account) { Optional<Application> app = applicationRepository.findApplicationByJob(application.getJobOffer().getId(), application.getUser().getId()); if (app.isPresent()) throw new AlreadyAppliedException(); //check if exist in DB/already applied try { application.setStatus(Application.Status.SEND); String jobApplierUrl = application.getJobOffer().getLinkToOffer(); JobApplier applier= resolveApplier(jobApplierUrl).orElseThrow(FormNotSupported::new); // finds JobApplier for specific website or throws empty FormNotSupported applier.applyForJob(application.getJobOffer(),profileData,application.getMessage(),application.getDocuments(),account); } catch (JobOfferArchivedException | JobOfferNotFound e) { //it is thrown when offer is not found on website. Still exist in application DB. application.setStatus(Application.Status.FAILED); application.setNotes("{JobOffer is either archived or not found}"); application.getJobOffer().setArchived(true); throw e; }catch(FormNotSupported e){ application.setStatus(Application.Status.FAILED); application.setNotes("{Not supported application. Try apply manually}"); if(e.getUrlPage()==null) //if FormNotSupprted does not contain Url to redirected page, that means JobApplier has not been found. Stop and rethrow Exception throw e; //try with another applier: application.getJobOffer().setLinkToOffer(e.getUrlPage()); //update JobOffer link with new redirected website Url from we can apply for job try{ apply(application,profileData,account ); // recurrent method }catch (FormNotSupported ex){ //if another applier failed rethrow FormNotSupported throw e; } }catch (ApplierException e){ application.setNotes(String.format("{Something went wrong. Details: %s }",e.getMessage())); application.setStatus(Application.Status.FAILED); throw e; }finally { applicationRepository.saveApplication(application); jobOfferService.archiveJob(application.getJobOffer()); } } //finds proper JobApplier based on Url address private Optional<JobApplier> resolveApplier(String url){ for(PortalType p:appliers.keySet()){ if(url.contains(p.getAddress())) return Optional.of(appliers.get(p)); } return Optional.empty(); } }
I have doubts if this code is ok. Is there another different solution to solve it?