Been stuck on a problem for a while now and searched every possible post but can't find why jersey is ignoring my security annotation?
Basically my Resource Config looks like so
#ApplicationPath("/*")
public class ApplicationResourceConfig extends ResourceConfig {
public ApplicationResourceConfig()
{
packages("com.property");
register(org.springframework.web.context.request.RequestContextListener.class);
register(org.glassfish.jersey.servlet.ServletContainer.class);
register(org.glassfish.jersey.server.spring.SpringLifecycleListener.class);
register(org.glassfish.jersey.server.validation.ValidationFeature.class);
register(org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature.class);
}
}
My Secuirity Context is defined as so;
#Provider
public class Authorizer implements javax.ws.rs.core.SecurityContext {
private final Account account;
private final Session session;
private final Principal principal;
public Authorizer() {
super();
this.account = null;
this.session = null;
this.principal = null;
}
public Authorizer(Account account, Session session) {
this.account = account;
this.session = session;
this.principal = new Principal() {
public String getName() {
return account.getAlias();
}
};
}
#Override
public String getAuthenticationScheme() {
return Authorizer.BASIC_AUTH;
}
#Override
public Principal getUserPrincipal() {
return principal;
}
#Override
public boolean isSecure() {
//return "https".equals(uriInfo.get().getRequestUri().getScheme());
return true;
}
#Override
public boolean isUserInRole(String role) {
if ((role == null) || (session == null) || (!session.isValidSession()) || (this.session.getType() == null) || (account == null))
return false;
return this.session.getType().toString().equals(role);
}
}
Security Filter looks like so
#Provider
#PreMatching
public class SecurityFilter implements ContainerRequestFilter {
#Inject
javax.inject.Provider<UriInfo> uriInfo;
#Autowired
private HibernateSessionFacotry sessionFactory;
#Override
public void filter(ContainerRequestContext request) {
try
{
String sessionKey = request.getHeaderString("Authorization");
Integer uid = request.getHeaderString("From") == null ? null : Integer.parseInt(request.getHeaderString("From"));
if ((sessionKey == null) || (uid == null))
return;
Session session = null;
Account account = null;
session = sessionFactory.getSessionDAO().verifySession(uid, sessionKey);
if (session != null)
account = session.getAccount();
if (
(session != null)
&& (account != null)
&& (session.getSessionKey().equals(sessionKey))
&& (session.getAccountId() == uid)
&& (session.isValidSession())
)
request.setSecurityContext(new Authorizer(account, session));
else
request.setSecurityContext(new Authorizer());
}
catch (Exception ex)
{
//TODO:: ONLY PRINT IN DEBUG MODE
ex.printStackTrace();
return;
}
}
}
My Resources
#Path("/account")
public class AccountImpl implements Account{
#POST
#DenyAll
#Audit
#NotNull #ValidAccount
public com.property.db.entities.account.Account createAccount
(
#NotNull #ValidPostAccount final com.property.db.entities.account.Account account,
#Context HttpServletRequest request
) throws NoSuchAlgorithmException, MandrillApiError, IOException;
}
But for some reason the security annotation #DenyAll gets ignored and I get a 200 response. Any reason why this is happening as I am completely baffled right now.
EDIT::
Just noticed that the security annotation are only ignored from my grizzly servlet any idea why this is happening?
public class WebTest extends JerseyTest {
protected static SimpleDateFormat sdf = null;
protected static GensonProvider gesonProvider = null;
protected static HibernateSessionFacotry sessionFactory = null;
#Override
protected Application configure() {
enable(TestProperties.LOG_TRAFFIC);
enable(TestProperties.DUMP_ENTITY);
return new ApplicationResourceConfig();
}
#Override
protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
return new TestContainerFactory() {
#Override
public TestContainer create(final URI baseUri, ApplicationHandler application)
throws IllegalArgumentException {
return new TestContainer() {
private HttpServer server;
#Override
public ClientConfig getClientConfig() {
return null;
}
#Override
public URI getBaseUri() {
return baseUri;
}
#Override
public void start() {
try {
this.server =
GrizzlyWebContainerFactory.create(baseUri);
WebappContext context = new WebappContext("WebappContext", "");
context.addContextInitParameter("contextConfigLocation", "classpath:applicationContext.xml");
context.addListener(org.springframework.web.context.ContextLoaderListener.class);
ServletRegistration registration = context.addServlet("ServletContainer", org.glassfish.jersey.servlet.ServletContainer.class);
registration.addMapping("/*");
registration.setInitParameter("jersey.config.server.provider.packages", "com.property.filters.auditing;com.property.filters.security;com.property.filters.versioning;com.property.resources");
registration.setInitParameter("com.sun.jersey.config.feature.Trace", "true");
context.deploy(server);
} catch (ProcessingException e) {
throw new TestContainerException(e);
} catch (IOException e) {
throw new TestContainerException(e);
}
}
#Override
public void stop() {
this.server.stop();
}
};
}
};
}
public void setUp() throws Exception {
super.setUp();
sdf = new SimpleDateFormat("dd/MM/yyyy");
assertNotNull(sdf);
gesonProvider = new GensonProvider();
assertNotNull(gesonProvider);
sessionFactory = new HibernateSessionFacotry();
assertNotNull(sessionFactory);
}
public void tearDown() throws Exception {
super.tearDown();
}
}
Related
I need to remove the soapAction from this header:
Headers: {Accept=[*/*], SOAPAction ["http://www.ya.ru/mybank/method/getDollars"]}
My configuration looks like this:
#PostConstruct
public void initialization(){
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(MyClass.class);
factory.setAddress(myWsdlUrl);
service = (MyClass) factory.create();
Client client = ClientProxy.getClient(service);
}
#Bean
public SAAJMetaFactory messageFactory(){
return new SAAJMetaFactoryImpl();
}
In the class of service I make such a request:
#Service
public class MyIntegrationImpl implements MyIntegration {
private MyClass service;
public MyIntegrationImpl(MyClass service) {
this.service = service;
}
#Override
public Info getVpc(ReqClass req, String clientPhone) {
return service.getInfo(req, clientPhone);
}
}
I found this code, but I do not know how to apply it:
public class RemoveActionHandler implements SOAPHandler<SOAPMessageContext> {
#Override
public Set<QName> getHeaders() {
System.out.println("Server : getHeaders()");
return null;
}
#Override
public boolean handleMessage(SOAPMessageContext context) {
if ("".equals(context.get(BindingProvider.SOAPACTION_URI_PROPERTY)))
context.put(BindingProvider.SOAPACTION_URI_PROPERTY, null);
return true;
}
#Override
public boolean handleFault(SOAPMessageContext context) {
System.out.println("Server : handleFault()");
return true;
}
#Override
public void close(MessageContext context) {
System.out.println("Server : close()");
}
}
This code can remove the required header
It was necessary to create an interceptor:
public class ServiceMyInterceptor extends AbstractSoapInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceMyInterceptor.class);
public ServiceMyInterceptor() {
super(Phase.USER_PROTOCOL);
addAfter(ReadHeadersInterceptor.class.getName());
addAfter(EndpointSelectionInterceptor.class.getName());
}
#Override
public void handleMessage(SoapMessage message) throws Fault {
Map<String, List<String>> headers = CastUtils.cast((Map)message.get(Message.PROTOCOL_HEADERS));
if (headers != null) {
List<String> sa = headers.get("SOAPAction");
String action = null;
if (sa != null && sa.size() > 0) {
action = sa.get(0);
}
LOGGER.info("Remove SOAPAction who equals {}", action);
headers.remove("SOAPAction");
}
}
}
And apply it this way:
#PostConstruct
public void initialization(){
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(MyClass.class);
factory.setAddress(myWsdlUrl);
service = (MyClass) factory.create();
Client client = ClientProxy.getClient(service);
ServiceMyInterceptor interceptor = new ServiceMyInterceptor();
client.getEndpoint().getOutInterceptors().add(interceptor);
}
If you judge by logs, then the SOAPAction header is gone.
I have configured a security-interceptor which should have the user-session object (which is a singleton) injected here is what I tried:
public DependencyInjection extends AbstractModule{
//Class that has AccessLevel Annoation
bind(InterfaceA.class).to(ImplA.class);
bind(UserPersistor.class).to(UserPersistorImpl.class);
//My session that I wish to inject
bind(UserSession.class).to(UserSessionHandler.class);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AccessLevel.class),
new SecurityInterceptor(getProvider(UserSession.class)));
}
Here my UserSessionHandler:
#Singleton
public class UserSessionHandler implements UserSession {
private UserLevel userLevel = UserLevel.DEFAULT;
private final UserPersistor userPersistor;
#Inject
public UserSessionHandler(UserPersistor userPersistor) {
this.userPersistor = userPersistor;
}
#Override
public boolean loginUser(String userName, String password) {
Benutzer user = userPersistor.getUserByName(userName);
if (user == null) {
return false;
} else {
if (user.getKennwort().equals(password)) {
userLevel = UserLevel.valueOf(user.getRolleId().getBezeichnung().toUpperCase());
return true;
} else {
return false;
}
}
}
#Override
public boolean logoutUser() {
userLevel = UserLevel.DEFAULT;
return true;
}
#Override
public UserLevel getUserLevel() {
return userLevel;
}
}
Here how the SecurityInterceptor currently looks like:
#Singleton
public class SecurityInterceptor implements MethodInterceptor {
private final Provider<UserSession> session;
#Inject
public SecurityInterceptor(Provider<UserSession> session){
this.session = session;
}
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
AccessLevel[] acessRoles = invocation.getMethod().getAnnotationsByType(AccessLevel.class);
List<UserLevel> allowedRoles = new ArrayList<>();
for(AccessLevel accessRole: acessRoles){
allowedRoles.add(accessRole.value());
}
//Make sure that User has one of the allowed Access-Levels
if (!allowedRoles.contains(session.get().getUserLevel())) {
throw new InvalidAccessException("No Access allowed with userlevel" + session.get().getUserLevel());
}
return invocation.proceed();
}
}
Now I managed to get it working in my Mockito-Test with a binding to an instance like this:
bind(MockInterface.class).to(MockClass.class);
bind(UserSession.class).toInstance(user);
bind(UserPersistor.class).toInstance(mockUserPersistor);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AccessLevel.class),
new SecurityInterceptor(getProvider(UserSession.class)));
However I don't want to create an instance myself but want the once guice is creating. How can I do that, or what am I currently doing wrong?
EDIT: My main issue is that the usersession seems to be different to the one that is generated. Here a simple example:
Injector injector = Guice.createInjector(new DependencyInjection());
UserSession session = injector.createInstance(UserSession.class);
InterfaceA methodCaller = injector.createInstance(InterfaceA.class);
if(session.loginUser("a","b")){
System.out.println(session.getUserLevel().toString()); //Returns Admin
}
methodCaller.callMethodWithAnnotation();
Now when I check the session.getUserLevel in the interceptor I get "Default"
EDIT2: My endgoal is to have the same session instance in my interceptor and anywhere I used UserSession
So my problem is this essentially:
http://i.imgur.com/rE0z7Um.png
Here is the class that throws the error once the response is called in the #Test method:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ComponentScan
#Import(RepositoryRestMvcAutoConfiguration.class)
public class AjaxControllerTest {
static final String DEFAULT_URI = "/api/some_function";
SomeObjects someObjects;
#Autowired
private TestRestTemplate restTemplate;
#Before
public void setUp() {
SortedSet<SomeObject> someObjectsSet = new TreeSet<>();
someObjectsSet.add(new SomeObject());
someObjectsSet.add(new SomeObject());
someObjects = new SomeObjects(someObjectsSet);
}
#Test
public void testGetFullJsonSuccessful() {
ResponseEntity<SomeObjects> response = this.restTemplate.postForEntity(DEFAULT_URI, someObjects, SomeObjects.class);
assertThat(response).isNotNull();
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
assertThat(response.getBody()).isNotNull();
}
}
Here is the AjaxController class function:
#PostMapping(value = "/api/some_function", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> someFunction(#RequestBody SomeObjects someObjects, Errors errors) {
AjaxResponseBody result = new AjaxResponseBody();
if (errors.hasErrors()) {
result.setMsg(errors.getAllErrors().stream().map(x -> x.getDefaultMessage()).collect(Collectors.joining(";")));
return ResponseEntity.badRequest().body(result);
}
Set<SomeObject> someObjectsSet = new TreeSet<>();
if (someObjectsSet.isEmpty()) {
result.setMsg("No data found.");
} else {
result.setMsg("Success");
}
result.setResult(someObjectsSet);
return ResponseEntity.ok(result);
}
Ajax Response object:
public class AjaxResponseBody {
private String msg;
private Set<SomeObject> result;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Set<SomeObject> getResult() {
return result;
}
public void setResult(Set<SomeObject> result) {
this.result = result;
}
}
and Involved POJOs:
public class SomeObject implements Comparable<SomeObject> {
private String str;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SomeObject that = (SomeObject) o;
return str != null ? str.equals(that.str) : that.str == null;
}
#Override
public int hashCode() {
return str != null ? str.hashCode() : 0;
}
#Override
public int compareTo(SomeObject o) {
return 0;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
}
public class SomeObjects {
private SortedSet<SomeObject> someObjects;
public SomeObjects(SortedSet<SomeObject> someObjects) {
this.setSomeObjects(someObjects);
}
public SomeObjects() {
}
public SortedSet<SomeObject> getSomeObjects() {
return someObjects;
}
public void setSomeObjects(SortedSet<SomeObject> someObjects) {
this.someObjects = someObjects;
}
}
Sorry for the code spam, but I want to be complete and I can't trace the problem myself. If I get an answer I will edit and trim down the unimportant code.
I've been working on a spring security recently and I know how I can define intercept-url (in Spring Security) dynamically using a Database.
but i need restart my web application to load defined intercept-url from database. But i need to load when i add a new intercept-url to database.
#Component
public class FilterInvocationServiceSecurityMetadataSourceBeanPostProcessor implements BeanPostProcessor {
#Autowired
private FilterInvocationServiceSecurityMetadataSource metadataSource;
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof FilterInvocationSecurityMetadataSource) {
return metadataSource;
}
if(bean instanceof FilterChainProxy.FilterChainValidator) {
return new FilterChainProxy.FilterChainValidator() {
#Override
public void validate(FilterChainProxy filterChainProxy) {
}
};
}
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
#Component("filterInvocationServiceSecurityMetadataSource")
public class FilterInvocationServiceSecurityMetadataSource implements FilterInvocationSecurityMetadataSource, InitializingBean{
private FilterInvocationSecurityMetadataSource delegate;
private RequestConfigMappingService requestConfigMappingService;
private SecurityExpressionHandler<FilterInvocation> expressionHandler;
#Autowired
public FilterInvocationServiceSecurityMetadataSource(CustomWebSecurityExpressionHandler expressionHandler,
RequestConfigMappingService filterInvocationService) {
this.expressionHandler = expressionHandler;
this.requestConfigMappingService = filterInvocationService;
}
public Collection<ConfigAttribute> getAllConfigAttributes() {
return this.delegate.getAllConfigAttributes();
}
public Collection<ConfigAttribute> getAttributes(Object object) {
return this.delegate.getAttributes(object);
}
public boolean supports(Class<?> clazz) {
return this.delegate.supports(clazz);
}
#Override
public void afterPropertiesSet() throws Exception {
List<RequestConfigMapping> requestConfigMappings = requestConfigMappingService.getRequestConfigMappings();
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>(requestConfigMappings.size());
for(RequestConfigMapping requestConfigMapping : requestConfigMappings) {
RequestMatcher matcher = requestConfigMapping.getMatcher();
requestMap.put(matcher,requestConfigMapping.getAttributes());
}
this.delegate = new ExpressionBasedFilterInvocationSecurityMetadataSource(requestMap, expressionHandler);
}
}
#Repository("requestConfigMappingService")
public class JdbcRequestConfigMappingService implements RequestConfigMappingService {
private SecurityFilterMetaDataService securityFilterMetaDataService;
#Autowired
public JdbcRequestConfigMappingService(SecurityFilterMetaDataService securityFilterMetaDataService) {
if (securityFilterMetaDataService == null) {
throw new IllegalArgumentException("securityFilterMetaDataService cannot be null");
}
this.securityFilterMetaDataService = securityFilterMetaDataService;
}
#Override
public List<RequestConfigMapping> getRequestConfigMappings() {
String pattern = "";
String expressionString = "";
List<SecurityFilterMetaData> securityFilterMetaDataList = securityFilterMetaDataService.getByAscOrder("sortOrder");
List<RequestConfigMapping> requestConfigMappings = new ArrayList<>();
for (SecurityFilterMetaData securityFilterMetaData : securityFilterMetaDataList) {
pattern = securityFilterMetaData.getAntPattern();
expressionString = securityFilterMetaData.getExpression();
AntPathRequestMatcher matcher = new AntPathRequestMatcher(pattern);
requestConfigMappings.add(new RequestConfigMapping(matcher, new SecurityConfig(expressionString)));
}
return requestConfigMappings;
}
private static final class RequestConfigMappingMapper implements RowMapper<RequestConfigMapping> {
#Override
public RequestConfigMapping mapRow(ResultSet rs, int rowNum) throws SQLException {
String pattern = rs.getString("ant_pattern");
String expressionString = rs.getString("expression");
AntPathRequestMatcher matcher = new AntPathRequestMatcher(pattern);
return new RequestConfigMapping(matcher, new SecurityConfig(expressionString));
}
}
}
public interface RequestConfigMappingService {
List<RequestConfigMapping> getRequestConfigMappings();
}
public final class RequestConfigMapping {
private final RequestMatcher matcher;
private final Collection<ConfigAttribute> attributes;
public RequestConfigMapping(RequestMatcher matcher, ConfigAttribute attribute) {
this(matcher, Collections.singleton(attribute));
}
public RequestConfigMapping(RequestMatcher matcher, Collection<ConfigAttribute> attributes) {
if (matcher == null) {
throw new IllegalArgumentException("matcher cannot be null");
}
Assert.notEmpty(attributes, "attributes cannot be null or emtpy");
this.matcher = matcher;
this.attributes = attributes;
}
public RequestMatcher getMatcher() {
return matcher;
}
public Collection<ConfigAttribute> getAttributes() {
return attributes;
}
}
At last I found answer. FilterInvocationServiceSecurityMetadataSource must change.
NOTE: Keep in mind that getAttributes will be invoked for every request that Spring Security intercepts so you will most likely want some sort of caching.
#Component("filterInvocationServiceSecurityMetadataSource")
public class FilterInvocationServiceSecurityMetadataSource implements FilterInvocationSecurityMetadataSource, InitializingBean{
private FilterInvocationSecurityMetadataSource delegate;
private RequestConfigMappingService requestConfigMappingService;
private SecurityExpressionHandler<FilterInvocation> expressionHandler;
#Autowired
public FilterInvocationServiceSecurityMetadataSource(CustomWebSecurityExpressionHandler expressionHandler,
RequestConfigMappingService filterInvocationService) {
this.expressionHandler = expressionHandler;
this.requestConfigMappingService = filterInvocationService;
}
public Collection<ConfigAttribute> getAllConfigAttributes() {
return this.delegate.getAllConfigAttributes();
}
public Collection<ConfigAttribute> getAttributes(Object object) {
List<RequestConfigMapping> requestConfigMappings = requestConfigMappingService.getRequestConfigMappings();
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>(requestConfigMappings.size());
for(RequestConfigMapping requestConfigMapping : requestConfigMappings) {
RequestMatcher matcher = requestConfigMapping.getMatcher();
requestMap.put(matcher,requestConfigMapping.getAttributes());
}
this.delegate = new ExpressionBasedFilterInvocationSecurityMetadataSource(requestMap, expressionHandler);
return this.delegate.getAttributes(object);
}
public boolean supports(Class<?> clazz) {
return this.delegate.supports(clazz);
}
#Override
public void afterPropertiesSet() throws Exception {
List<RequestConfigMapping> requestConfigMappings = requestConfigMappingService.getRequestConfigMappings();
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>(requestConfigMappings.size());
for(RequestConfigMapping requestConfigMapping : requestConfigMappings) {
RequestMatcher matcher = requestConfigMapping.getMatcher();
requestMap.put(matcher,requestConfigMapping.getAttributes());
}
this.delegate = new ExpressionBasedFilterInvocationSecurityMetadataSource(requestMap, expressionHandler);
}
}
I made a DAO class with factory method and the specific DAO returns singleton, a single instance of the DAO. But I been tracing it and its being created but I try to call on it and it always null.
Just to explain the storage factory
I call on DAOFactory to get RAMDAOFactory to get to RAMUserDAO
If there is better way to handle RAM, Serialization and SQL type DAOs or CRUD please let me know.
class that I'm calling the storage from.
public class Registration
{
private UserDAO userStorage;
private static Logger log = LogClass.getLog();
Registration(DAOFactoryType typeDataStorage)
{
userStorage = DAOFactory.getDAOFactory(typeDataStorage).getUserDAO();
log.trace("insdie Reg");
}
void addUser(String userName, String password, UserType... args)
throws Exception
{
List<UserType> userTypes = new ArrayList<UserType>(args.length);
for (UserType userType : args)
{
log.trace("userType " + userType);
userTypes.add(userType);
}
User newUser = new DefaultUser(userName, password, userTypes);
log.trace("newUser " + newUser);
if (userStorage != null)
{
userStorage.insert(newUser);
}
else
{
log.trace("userStorage null");
}
}
}
This is my DAOFactory
public abstract class DAOFactory
{
private static Logger log = LogClass.getLog();
public abstract TradeDAO getTradeDAO();
public abstract UserDAO getUserDAO();
public abstract LogDAO getLogDAO();
public static DAOFactory getDAOFactory(DAOFactoryType factoryType)
{
switch (factoryType)
{
case SQL:
return new SQLDAOFactory();
case RAM:
log.trace("insdie RAM");
return new RAMDAOFactory();
case SERIAL:
return new SerialDAOFactory();
default:
return null;
}
}
}
RAMDAOFactory
public class RAMDAOFactory extends DAOFactory
{
private static Logger log = LogClass.getLog();
private TradeDAO ramTradeDAO;
private UserDAO ramUserDAO;
private LogDAO ramLogDAO;
public RAMDAOFactory()
{
log.trace("insdie RAMDAOFactory");
RAMUserDAO.getRAMUserDAO();
RAMTradeDAO.getRAMTradeDAO();
RAMLogDAO.getRAMLogDAO();
}
#Override
public TradeDAO getTradeDAO()
{
return ramTradeDAO;
}
#Override
public UserDAO getUserDAO()
{
return ramUserDAO;
}
#Override
public LogDAO getLogDAO()
{
return ramLogDAO;
}
}
This is my UserDAO
public class RAMUserDAO implements UserDAO
{
/*
* Map<Integer, List<byte[]>> userHash; List<byte[]> arrayHashSalt;
*/
private static RAMUserDAO userDAO = null;
private Map<String, User> userList;
private static Logger log = LogClass.getLog();
private RAMUserDAO()
{
userList = new HashMap<String, User>();
log.trace("insdie RAMUserDAO constructor");
}
public static RAMUserDAO getRAMUserDAO()
{
log.trace("insdie getRAMUserDAO");
if(userDAO == null) {
log.trace("insdie new RAMUserDAO()");
userDAO = new RAMUserDAO();
}
/*if (userDAO == null)
{
synchronized (RAMUserDAO.class)
{
if (userDAO == null)
{
userDAO = new RAMUserDAO();
}
}
}*/
return userDAO;
}
#Override
public void insert(User user) throws Exception
{
log.trace("insdie insert");
userList.put(user.getUserName(), user);
}
}
The oversight was in RAMDAOFactory and fix was:
public class RAMDAOFactory extends DAOFactory
{
private static Logger log = LogClass.getLog();
#Override
public TradeDAO getTradeDAO()
{
return RAMTradeDAO.getRAMTradeDAO();
}
#Override
public UserDAO getUserDAO()
{
return RAMUserDAO.getRAMUserDAO();
}
#Override
public LogDAO getLogDAO()
{
return RAMLogDAO.getRAMLogDAO();
}
}
You've called the methods
public RAMDAOFactory()
{
log.trace("insdie RAMDAOFactory");
RAMUserDAO.getRAMUserDAO();
RAMTradeDAO.getRAMTradeDAO();
RAMLogDAO.getRAMLogDAO();
}
but you haven't assigned their value to anything
#Override
public UserDAO getUserDAO()
{
return ramUserDAO;
}
Either always call
RAMUserDao.getRAMUserDAO();
when you want to return the UserDAO or assign it to ramUserDAO and return that.