Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

org.apache.catalina.core.StandardContext.startInternal One or more listeners failed to start

I work on a Java/Spring/ Apache Cxf web app and suddenly, I get the error while I made some apparently naive changes,

25-Aug-2017 11:48:43.036 INFO [RMI TCP Connection(2)-127.0.0.1] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
log4j:WARN No appenders could be found for logger (org.apache.cxf.common.logging.LogUtils).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
25-Aug-2017 11:48:43.540 SEVERE [RMI TCP Connection(2)-127.0.0.1] org.apache.catalina.core.StandardContext.startInternal One or more listeners failed to start. Full details will be found in the appropriate container log file
25-Aug-2017 11:48:43.554 SEVERE [RMI TCP Connection(2)-127.0.0.1] org.apache.catalina.core.StandardContext.startInternal Context [] startup failed due to previous errors
[2017-08-25 11:48:43,586] Artifact jaxrs-tutorials:war exploded: Error during artifact deployment. See server log for details.
25-Aug-2017 11:48:49.258 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/Applications/Tomcat-8.5.16/webapps/manager]
25-Aug-2017 11:48:49.310 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/Applications/Tomcat-8.5.16/webapps/manager] has finished in [51] ms

I guess this is the main info of the error,

25-Aug-2017 11:48:43.540 SEVERE [RMI TCP Connection(2)-127.0.0.1] org.apache.catalina.core.StandardContext.startInternal One or more listeners failed to start. Full details will be found in the appropriate container log file
25-Aug-2017 11:48:43.554 SEVERE [RMI TCP Connection(2)-127.0.0.1] org.apache.catalina.core.StandardContext.startInternal Context [] startup failed due to previous errors

The project structure is provided,

enter image description here

The config directory is utilized for the Java annotation based config and code is provided below.

The AppConfig file,

@Configuration
@ComponentScan(AppConfig.SERVICE_PACKAGE)
public class AppConfig {

    public static final String BASE_PACKAGE = "mobi.puut";
    public static final String SERVICE_PACKAGE = BASE_PACKAGE + ".services";
    private static final String RESOURCES_PACKAGE = BASE_PACKAGE + ".rest";
    private static final String PROVIDER_PACKAGE = BASE_PACKAGE + ".rest.provider";

    public static final String API_BASE = "/api/*";

    @ApplicationPath("/")
    public class JaxRsApiApplication extends Application {
    }

    @Bean(destroyMethod = "shutdown")
    public SpringBus cxf() {
        return new SpringBus();
    }

    @Bean
    @DependsOn("cxf")
    public Server jaxRsServer(ApplicationContext appContext) {
        JAXRSServerFactoryBean factory = RuntimeDelegate.getInstance().createEndpoint(jaxRsApiApplication(), JAXRSServerFactoryBean.class);
        factory.setServiceBeans(restServiceList(appContext));
        factory.setAddress("/" + factory.getAddress());
        factory.setProviders(restProviderList(appContext, jsonProvider()));
        return factory.create();
    }

    @Bean
    public JaxRsApiApplication jaxRsApiApplication() {
        return new JaxRsApiApplication();
    }

    @Bean
    public JacksonJsonProvider jsonProvider() {
        return new JacksonJsonProvider();
    }

    private List<Object> restServiceList(ApplicationContext appContext) {
        return RestServiceBeanScanner.scan(appContext, AppConfig.RESOURCES_PACKAGE);
    }

    private List<Object> restProviderList(final ApplicationContext appContext,
                                          final JacksonJsonProvider jsonProvider) {
        final List<Object> providers = RestProviderBeanScanner.scan(appContext, PROVIDER_PACKAGE);
        providers.add(jsonProvider);
        return providers;
    }

}

The WebInitializer is provided,

public class WebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        servletContext.addListener(new ContextLoaderListener(createWebAppContext()));
        addApacheCxfServlet(servletContext);
    }

    private void addApacheCxfServlet(ServletContext servletContext) {
        CXFServlet cxfServlet = new CXFServlet();

        ServletRegistration.Dynamic appServlet = servletContext.addServlet("CXFServlet", cxfServlet);
        appServlet.setLoadOnStartup(1);

        Set<String> mappingConflicts = appServlet.addMapping(AppConfig.API_BASE);
    }

    private WebApplicationContext createWebAppContext() {
        AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
        appContext.register(AppConfig.class);
        return appContext;
    }

}

I have seen the similar questions to the platform and those don't help me out and I have so little info to solve the issue.

How can I use logger to get more info and where I should utilize them? Also, any insight about solving the issue will be helpful. I have updated the JAR files with mvn clean install and mvn idea:idea commands.

UPDATE

Tomcat Localhost Log

enter image description here

Tomcat Catalina Log

enter image description here

like image 693
Heisenberg Avatar asked Aug 25 '17 05:08

Heisenberg


1 Answers

I would like to write a detailed answer on the issue and the steps I have followed to solve the problem.

A. There was not enough logging info. I looked up the POM and found this,

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
            <exclusions>
                <!-- Exclude Commons Logging in favor of SLF4j -->
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

I have excluded the logging in the favour of SLF4J and I just deleted the exclusion XML tag to get more logging info. So, it becomes like this,

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

B. Now, I get the logging info. I have this error message like,

Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'userService' for bean class [mobi.puut.services.UserServiceImpl] conflicts with existing, non-compatible bean definition of same name and class [mobi.puut.services.UserService2Impl]

You get the ConflictingBeanDefinitionException for creating the bean with the same name. Though I have some experience with the Spring, I need to create with a project with the Apache Cxf and hence, clone a demo project for the very purpose. They have the one same entity User and same definition - interface and same implementation of that. Though I have refactored to all classes in the project and there seem no apparent errors, I still keep an issue - I keep the same bean name "userService in 2 implementations of the interface.

The User2 class in the entities,

public class User2 {

    private Integer id;
    private String name;

    public User2() {
    }

    public User2(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return String.format("{id=%s,name=%s}", id, name);
    }
}

The User class in the entities,

@Entity
@Table(name = "users")
public class User {

    @Id
    @Column
    @NotNull
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @NotNull
    @Column(name = "name")
    @Size(min = 5, max = 45, message = "Name must be between 5 and 45 characters.")
    private String name;

    public User() {

    }

    public User(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    public User(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof User)) return false;

        User user = (User) o;

        if (getId() != user.getId()) return false;
        return getName().equals(user.getName());
    }

    @Override
    public int hashCode() {
        int result = getId();
        result = 31 * result + getName().hashCode();
        return result;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

The interfaces in the services directories,

public interface IUserService2 {

    Collection<User2> getUsers();

    User2 getUser(Integer id);

    Response add(User2 user);
}



public interface IUserService {

    List<User> getCurrentStatuses();

    void create(User user);

    List<User> getAllUsers();
}

The implementations of the interfaces inside the services derectory,

@Service("userService")
public class UserService2Impl implements IUserService2 {

    private static Map<Integer, User2> users = new HashMap<Integer, User2>();

    static {
        users.put(1, new User2(1, "foo"));
        users.put(2, new User2(2, "bar"));
        users.put(3, new User2(3, "baz"));
    }

    public UserService2Impl() {
    }

    @Override
    public Collection<User2> getUsers() {
        return users.values();
    }

    @Override
    public User2 getUser(Integer id) {
        return users.get(id);
    }

    @Override
    public Response add(User2 user) {
        user.setId(users.size()+1);
        users.put(user.getId(), user);

        //do more stuff to add user to the system..
        return Response.status(Response.Status.OK).build();
    }

}


@Service("userService")
public class UserServiceImpl implements IUserService {

    @Autowired
    @Qualifier("userDao")
    public IUserDao userDao;

    public List<User> getCurrentStatuses() {
        return userDao.getAllUsers();
    }

    public void create(User user) {
        userDao.saveOrUpdate(user);
    }

    public List<User> getAllUsers() {
        List<User> users = userDao.getAllUsers();

        if (Objects.isNull(users)) {
            return null;
        }
        return users;
    }
}

And, there was the error - I annotaed 2 classes with the same bean name of "userService". I had to change it like this to provide the bean a different name,

@Service("user2Service")
public class UserService2Impl implements IUserService2 {

    // some code
}

And, that error goes away. In short, the error ConflictingBeanDefinitionException due to the 2 beans of the same name and I just had to provide a different name.

C. I still had things to fix. Afterwards, when I run the program, I get the

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'userDao'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'mobi.puut.database.IUserDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=userDao)}


// some consequent error messages not necessay to solve the issue

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'mobi.puut.database.IUserDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=userDao)}

The error here is UnsatisfiedDependencyException and says it can't create a bean with the name of userService. OK, this is the code I had and integrated into the project. The Unsatisfied dependency expressed through the field namely userDao. userDao is the instance of the interface of IUserDao and it was @autowired like this,

    @Autowired
    public IUserDao userDao;

Here is more insight of the code,

@Service("userService")
public class UserServiceImpl implements IUserService {

    @Autowired
    public IUserDao userDao;


     public List<User> getCurrentStatuses() {
        return userDao.getAllUsers();
    }

    public void create(User user) {
        userDao.saveOrUpdate(user);
    }

    public List<User> getAllUsers() {
        List<User> users = userDao.getAllUsers();

        if (Objects.isNull(users)) {
            return null;
        }
        return users;
    }
}

I have an interface in the database directory and consequent implementation of the interface for the user. The interface name is IUserDao and looks

soemthing like this, 


public interface IUserDao {

    boolean create(User user);

    void saveOrUpdate(User user);

    boolean create(List<User> users);

    List<User> getAllUsers();

    User getById(int id);
}

And, the implementation,

@Repository("userDao")
public class UserDaoImpl implements IUserDao {

    @Autowired
    private SessionFactory sessionFactory;

    // the HQL queries

}

The consequent part of the error message was NoSuchBeanDefinitionException and the app doesn't find a qualifying bean of the type (class) of IUserDao. I have all the HQL queries in the implementation of the IUserDao and the code works perfectly before.

I have to take a moment to think and finally, I have an intuition that may be the database layer is NOT integrated into the app. Here is the configuration I used,

public class WebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        servletContext.addListener(new ContextLoaderListener(createWebAppContext()));
        addApacheCxfServlet(servletContext);
    }

    private void addApacheCxfServlet(ServletContext servletContext) {
        CXFServlet cxfServlet = new CXFServlet();

        ServletRegistration.Dynamic appServlet = servletContext.addServlet("CXFServlet", cxfServlet);
        appServlet.setLoadOnStartup(1);

        Set<String> mappingConflicts = appServlet.addMapping(AppConfig.API_BASE);
    }

    private WebApplicationContext createWebAppContext() {
        AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();

        // register all the config classes here
        appContext.register(AppConfig.class);
        return appContext;
    }

}

Obviously, the no database code is integrated in the WebInitializer. I wrote a new class provides all the info of the database connection and the hibernate integration and looks like,

@Configuration
@EnableWebMvc
@EnableTransactionManagement
@ComponentScan(basePackages = {"mobi.puut.database"})
public class DatabaseConfig {

    @Bean
    public LocalSessionFactoryBean sessionFactory() {

        //  mobi.puut.entities
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(
                new String[]{"mobi.puut.entities"});
        sessionFactory.setHibernateProperties(hibernateProperties());

        return sessionFactory;
    }

    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(
            SessionFactory sessionFactory) {

        HibernateTransactionManager txManager
                = new HibernateTransactionManager();
        txManager.setSessionFactory(sessionFactory);

        return txManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    @Bean
    public DataSource dataSource() {

        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");

        // dataSource.setUrl("jdbc:mysql://localhost:3306/wallet?createDatabaseIfNotExist=true");
        dataSource.setUrl("jdbc:mysql://localhost:3306/Wallet");
        dataSource.setUsername("testuser");
        dataSource.setPassword("testpassword");

        return dataSource;
    }

    Properties hibernateProperties() {

        Properties properties = new Properties();
//        properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
        return properties;
    }
}

And, then finally integrate into the WebInitializer. This is the code I used to registered the config earlier in the WebInitializer,

appContext.register(AppConfig.class);

Updated the line with the,

appContext.register(AppConfig.class, DatabaseConfig.class);

Finally, everything works fine. So, the config directory looks like,

enter image description here

SUMMERY

I had to solve this problem through the 3 errors,

i. ConflictingBeanDefinitionException
ii. UnsatisfiedDependencyException
iii. NoSuchBeanDefinitionException

ConflictingBeanDefinitionException -> 2 beans with the same name

UnsatisfiedDependencyException -> Have a bean (= "userDao") in the class which was not correct to use

NoSuchBeanDefinitionException -> the code was correct but needed to add the datbase layer in the congig so the Spring IoC finds the bean.

I sincerely hope this will help some people.

like image 147
Heisenberg Avatar answered Nov 14 '22 09:11

Heisenberg