I have declared an aspect like the following
#Aspect
public class CacheMonitorImpl {
private final static Logger LOG = LoggerFactory
.getLogger(CacheMonitorImpl.class);
private final static NumberFormat NF = new DecimalFormat("0.0###");
#Autowired
private EntityManagerFactory entityManagerFactory;
#Around("execution(* aop.web.teacher.service..*.*(..))")
public Object log(ProceedingJoinPoint pjp) throws Throwable {
LOG.info("$$ Test Property :: " + testprop);
if (!LOG.isDebugEnabled()) {
LOG.info("####### Logger is not debug enabled"
+ entityManagerFactory);
return pjp.proceed();
}
HibernateEntityManagerFactory hbmanagerfactory = (HibernateEntityManagerFactory) entityManagerFactory;
SessionFactory sessionFactory = hbmanagerfactory.getSessionFactory();
Statistics statistics = sessionFactory.getStatistics();
statistics.setStatisticsEnabled(true);
long hit0 = statistics.getQueryCacheHitCount();
long miss0 = statistics.getSecondLevelCacheMissCount();
Object result = pjp.proceed();
long hit1 = statistics.getQueryCacheHitCount();
long miss1 = statistics.getQueryCacheMissCount();
double ratio = (double) hit1 / (hit1 + miss1);
if (hit1 > hit0) {
LOG.debug(String.format("CACHE HIT; Ratio=%s; Signature=%s#%s()",
NF.format(ratio), pjp.getTarget().getClass().getName(), pjp
.getSignature().toShortString()));
} else if (miss1 > miss0) {
LOG.debug(String.format("CACHE MISS; Ratio=%s; Signature=%s#%s()",
NF.format(ratio), pjp.getTarget().getClass().getName(), pjp
.getSignature().toShortString()));
} else {
LOG.debug("query cache not used");
}
return null;
}
}
Now the aspect method is getting invoked but I am getting null EntityManagerFactory. Please point me to the correct of doing this!
Thanks in advance.
Related
[ISSUE] repo always returns null when I call repo methods, while stepping through, throws null pointer exception. then front end receives
500: Http failure response for http://localhost:4200/api/aiprollout/updatecsv: 500 Internal Server Error
[HAVE TRIED] Adjusting AutoWired and components and service annotations.
[QUESTIONS]
1- Does every repo method need its own service and controller method?
2- Is it okay to create a new service that uses an existing controller?
3- If this new service uses SuperCsv and I create custom CsvCellProcessors, can these cell processors also call the repo? Should these cell processors perform logic? or should it be done else where? What class annotations should these cellProcessors classes have? #Component?
Any advice is greatly appreciated, feel a little lost at this point not even sure what to do.
[CODE]
Controller:
#RestController
#EnableConfigurationProperties({SpoofingConfigurationProperties.class})
#RequestMapping(value = "")
public class AipRolloutController {
private final Logger logger = some logger
private final AipRolloutService AipRolloutService;
private final CsvParserService csvParserService;
#Autowired
public AipRolloutController(AipRolloutService aipRolloutService, CsvParserService csvParserService) {
this.AipRolloutService = aipRolloutService;
this.csvParserService = csvParserService;
}
#PostMapping(value = "/updatecsv", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<?> processCsv(#RequestParam("csvFile") MultipartFile csvFile) throws IOException {
if (csvFile.isEmpty()) return new ResponseEntity(
responceJson("please select a file!"),
HttpStatus.NO_CONTENT
);
csvParserService.parseCsvFile(csvFile);
return new ResponseEntity(
responceJson("Successfully uploaded - " + csvFile.getOriginalFilename()),
new HttpHeaders(),
HttpStatus.CREATED
);
}
Service:
#Service
public class AipRolloutService {
private static final Logger logger = some logger
#Autowired
private AIPRolloutRepository AIPRolloutRepository;
New Csv parser Service
#Service
public class CsvParserService {
#Autowired private AipRolloutService aipRolloutService;
public CsvParserService(AipRolloutService aipRolloutService) {
this.aipRolloutService = aipRolloutService;
}
public void parseCsvFile(MultipartFile csvFile) throws IOException {
CsvMapReader csvMapReader = new CsvMapReader(new InputStreamReader(csvFile.getInputStream()), CsvPreference.STANDARD_PREFERENCE);
parseCsv(csvMapReader);
csvMapReader.close();
}
private void parseCsv(CsvMapReader csvMapReader) throws IOException {
String[] header = csvMapReader.getHeader(true);
List<String> headers = Arrays.asList(header);
verifySourceColumn(headers);
verifyPovColumn(headers);
final CellProcessor[] processors = getProcessors(headers);
Map<String, Object> csvImportMap = null;
while ((csvImportMap = csvMapReader.read(header, processors)) != null) {
CsvImportDTO csvImportDto = new CsvImportDTO(csvImportMap);
if ( activationTypeP(csvImportDto) ){
int mssValue = Integer.parseInt(csvImportDto.getMssValue());
aipRolloutService.updateAipRollout(csvImportDto.getSource(),
csvImportDto.getPov(),
csvImportDto.getActivationType(),
mssValue);
}
}
}
private CellProcessor[] getProcessors(List<String> headers) {
CellProcessor[] processors = new CellProcessor[headers.size()];
int index = 0;
for (String header : headers) {
if (header.contains(SOURCE_ID)) {
processors[index++] = new CsvSourceIdCellParser();
} else if (header.contains(POV)) {
processors[index++] = new CsvPovCellParser();
} else if (header.contains(ACTIVATION_TYPE)) {
processors[index++] = new CsvActivationTypeCellParser();
} else if (header.contains(ACTIVATION_DATE)) {
processors[index++] = new Optional();
} else if (header.contains(DEACTIVATION_DATE)) {
processors[index++] = new Optional();
} else if (header.contains(MSS_VALUE)) {
processors[index++] = new CsvMssValueCellParser();
} else {
processors[index++] = null; // throw exception? wrong header info instead of allowing null?
}
}
return processors;
}
Custom Cell Processor that calls repo and returns null
public class CsvSourceIdCellParser extends CellProcessorAdaptor {
#Autowired AIPRolloutRepository aipRolloutRepository;
public CsvSourceIdCellParser(){ super(); }
// this constructor allows other processors to be chained
public CsvSourceIdCellParser(CellProcessor next){ super(next); }
#Override
public Object execute(Object value, CsvContext csvContext) {
// throws an Exception if the input is null
validateInputNotNull(value, csvContext);
// get rid of description only need first 3 #'s
value = value.toString().substring(0,3);
// check if WH exists
if( aipRolloutRepository.dcExistsInDatabase(value.toString()) )
return value;
else
throw new RuntimeException("Check Warehouse Value, Value Not Found "
+ "Row number: " + csvContext.getRowNumber()
+ " Column number: " + csvContext.getColumnNumber());
}
}
Repository
#Repository
public class AIPRolloutRepository {
private static final Logger logger = LoggerFactory.getLogger(AIPRolloutRepository.class);
#Autowired
JdbcTemplate jdbcTemplate;
public AIPRolloutRepository() {
}
public boolean dcExistsInDatabase(String dc){
// Query for a count saves time and memory, query for distinct saves time and memory on execution
boolean hasRecord =
jdbcTemplate
.query( "select count (distinct '" + dc +"')" +
"from xxcus.XX_AIP_ROLLOUT" +
"where DC = '" + dc + "';",
new Object[] { dc },
(ResultSet rs) -> {
if (rs.next()) {
return true;
}
return false;
}
);
return hasRecord;
}
We have a gRPC server that inserts the data into the CockRoachDB and the data is coming from a Spring Boot micro-service.
This is my code to persist in the CRDB database:
#Service
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class CockroachPersister {
private static final String X_AMZN_REQUESTID = "x-amzn-RequestId";
private static final String X_AMZN_RESPONSE = "x-amzn-Response";
private static final String PUTITEM = "PutItem";
private static final String GETITEM = "GetItem";
private static final String DELETEITEM = "DeleteItem";
private static final String UPDATEITEM = "UpdateItem";
public <T extends Message> T save(final String requestBody, final String action, final String tableName) {
T t = null;
try {
List<GRPCMapper> lGRPCMapper = ServiceMapper.getServices(action,tableName);
for (GRPCMapper grpcMapper : lGRPCMapper) {
System.out.println("grpcMapper.getClassName() ==> "+grpcMapper.getClassName());
Class<?> className = Class.forName(grpcMapper.getClassName());
Class<?> implementedClassType = Class.forName(grpcMapper.getImplementedClass());
Method userMethod = implementedClassType.getDeclaredMethod(grpcMapper.getServiceName(), className);
System.out.println("userMethod\t" + userMethod.getName());
t = (T) userMethod.invoke(null, ProtoUtil.getInstance(requestBody, grpcMapper.getProtoType()));
System.out.printf("Service => %s row(s) Inserted \n", t.getAllFields().toString());
}
} catch (Exception e) {
e.printStackTrace();
}
return t;
}
}
If the initial insertion failed, I would like to try at least 3 TIMES before we can log the error. How do I implement that?
A solution that use message queue will be also acceptable.
My project uses springboot+springDataJpa+shiro.
Because my server database uses the master and salve method, so I need to call my code to connect to the two databases, I designed to use the AbstractRoutingDataSource + aop method. Now I have a problem, I think it may be caused by shiro.
I know that the connection switching is performed by the getconnection() method of AbstractRoutingDataSource, and I cannot manually control this method. The problem now is that my getconnection() is executed at most twice in an interface request. Let me post my code and describe it:
#Order(0)
#Aspect
#Component
public class RoutingAopAspect {
#Around("#annotation(targetDataSource)")
public Object routingWithDataSource(ProceedingJoinPoint joinPoint, TargetDataSource targetDataSource) throws Throwable {
try {
DynamicRoutingDataSourceContext.setRoutingDataSource(targetDataSource.value());
return joinPoint.proceed();
} finally {
DynamicRoutingDataSourceContext.removeRoutingDataSource();
}
}
}
public class DynamicRoutingDataSourceContext {
public static final String MASTER = "master";
public static final String SLAVE = "slave";
private static final ThreadLocal<Object> threadLocalDataSource = new ThreadLocal<>();
public static void setRoutingDataSource(Object dataSource) {
if (dataSource == null) {
throw new NullPointerException();
}
threadLocalDataSource.set(dataSource);
// System.err.println(Thread.currentThread().getName()+" set RoutingDataSource : " + dataSource);
}
public static Object getRoutingDataSource() {
Object dataSourceType = threadLocalDataSource.get();
if (dataSourceType == null) {
threadLocalDataSource.set(DynamicRoutingDataSourceContext.MASTER);
return getRoutingDataSource();
}
// System.err.println(Thread.currentThread().getName()+" get RoutingDataSource : " + dataSourceType);
return dataSourceType;
}
public static void removeRoutingDataSource() {
threadLocalDataSource.remove();
// System.err.println(Thread.currentThread().getName()+" remove RoutingDataSource");
}
}
#EnableTransactionManagement
#Configuration
public class DataSourceConfig {
#Value("${datasource.master.url}")
private String masterUrl;
#Value("${datasource.master.username}")
private String masterUsername;
#Value("${datasource.master.password}")
private String masterPassword;
#Value("${dataSource.driverClass}")
private String masterDriverClassName;
#Value("${datasource.slave.url}")
private String slaveUrl;
#Value("${datasource.slave.username}")
private String slaveUsername;
#Value("${datasource.slave.password}")
private String slavePassword;
#Value("${dataSource.driverClass}")
private String slaveDriverClassName;
#Bean(name = "masterDataSource")
public DataSource masterDataSource(){
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(masterUrl);
datasource.setUsername(masterUsername);
datasource.setPassword(masterPassword);
datasource.setDriverClassName(masterDriverClassName);
return datasource;
}
#Bean(name = "slaveDataSource")
public DataSource slaveDataSource(){
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(slaveUrl);
datasource.setUsername(slaveUsername);
datasource.setPassword(slavePassword);
datasource.setDriverClassName(slaveDriverClassName);
return datasource;
}
#Primary
#Bean
public DynamicRoutingDataSource dynamicDataSource(#Qualifier(value = "masterDataSource") DataSource masterDataSource,
#Qualifier(value = "slaveDataSource") DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>(2);
targetDataSources.put(DynamicRoutingDataSourceContext.MASTER, masterDataSource);
targetDataSources.put(DynamicRoutingDataSourceContext.SLAVE, slaveDataSource);
DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
dynamicRoutingDataSource.setTargetDataSources(targetDataSources);
dynamicRoutingDataSource.setDefaultTargetDataSource(masterDataSource);
dynamicRoutingDataSource.afterPropertiesSet();
return dynamicRoutingDataSource;
}
}
public class DynamicRoutingDataSourceContext {
public static final String MASTER = "master";
public static final String SLAVE = "slave";
private static final ThreadLocal<Object> threadLocalDataSource = new ThreadLocal<>();
public static void setRoutingDataSource(Object dataSource) {
if (dataSource == null) {
throw new NullPointerException();
}
threadLocalDataSource.set(dataSource);
// System.err.println(Thread.currentThread().getName()+" set RoutingDataSource : " + dataSource);
}
public static Object getRoutingDataSource() {
Object dataSourceType = threadLocalDataSource.get();
if (dataSourceType == null) {
threadLocalDataSource.set(DynamicRoutingDataSourceContext.MASTER);
return getRoutingDataSource();
}
// System.err.println(Thread.currentThread().getName()+" get RoutingDataSource : " + dataSourceType);
return dataSourceType;
}
public static void removeRoutingDataSource() {
threadLocalDataSource.remove();
// System.err.println(Thread.currentThread().getName()+" remove RoutingDataSource");
}
}
This is the relevant basic configuration of AbstractRoutingDataSource.
I defined an aspect to get the parameters of #TargetDataSource in the method. This parameter is a data source that needs to be executed currently. I think there is no problem with my configuration.
Then I will use #TargetDataSource on my service method, and I use shiro, shiro’s doGetAuthorizationInfo() method and doGetAuthenticationInfo() are executed before my service, and both methods need to call my userservice .
Then the problem now is that after calling the doGetAuthorizationInfo() and doGetAuthenticationInfo() methods, they will automatically execute the getconnection() method of AbstractRoutingDataSource to switch the data source, and then execute to my own service, it will not execute the getconnection() method. , This is what I said getconnection() is executed at most twice in an interface request.
#Slf4j
#Component
public class ShiroRealm extends AuthorizingRealm {
#Autowired
#Lazy
private UserService userService;
#Autowired
CacheUtil cacheUtil;
#Override
public boolean supports(AuthenticationToken token) {
return token instanceof JwtToken;
}
#Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = JwtUtil.getClaim(principals.toString(), "username");
User user = userService.getUserByUsername(username);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addRole(user.getRole());
return simpleAuthorizationInfo;
}
#Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) {
String token = (String) auth.getCredentials();
String username = JwtUtil.getClaim(token, "username");
if (username == null) {
throw new AuthenticationException("token invalid");
}
User user = userService.getUserByUsername(username);
if (user == null) {
throw new AuthenticationException("User didn't existed!");
}
if (JwtUtil.verify(token, username, user.getPassword(), TokenType.ACCESS_TOKEN) &&
cacheUtil.hasKey(CacheKey.ACCESS_TOKEN_KEY + token)
) {
return new SimpleAuthenticationInfo(token, token, "userRealm");
}
throw new AuthenticationException("Token expired or incorrect");
}
}
#Service
public class PageServiceImpl implements PageService {
#Autowired
PageRepository pageRepository;
#Override
#TargetDataSource("slave")
#Transactional(rollbackFor = Exception.class)
public List<Page> adminFindAll() {
List<Page> pageList = pageRepository.findAll();
if (pageList.isEmpty()) {
throw new CustomNotFoundException("page list not found");
}
return pageList;
}
}
I don’t know if my description is clear. If it is not clear, please ask questions. I hope to get your help, thanks very much!
I'm looking to use #Transactional in spring boot, but after several attempts i cannot get the transaction working despite having an exception inside to rollback, so I'm missing something ?
if an exception happened with WebSocketHandler.sendNotificationToVenue in serviceimpl
i wanna rollback with two insert statements ;(
Here is the ServiceImpl
#Service
#Slf4j
public class OrderInfoServiceImpl implements OrderInfoService {
#Resource
private OrderInfoMapper orderInfoMapper;
#Resource
private OrderDetailsMapper orderdetailsMapper;
#Resource
private WebSocketHandler webSockethHandler;
private OrderDetailsVO od = new OrderDetailsVO();
#Transactional(rollbackFor = Exception.class)
#Override
public Map<String, String> insertOrderInfo(OrderInfoVO order) throws Exception {
Map<String, String> rMap = new HashMap<>();
rMap.put("result", "false");
int oiSum = 0;
try {
for (int i = 0; i < order.getOdList().size(); i++) {
if (order.getOdList().get(i) != null) {
int price = order.getOdList().get(i).getMiPrice();
int qty = order.getOdList().get(i).getOdQuantity();
oiSum += price * qty;
}
}
order.setOiSum(oiSum);
String oiMsg = "";
for (int i = 0; i < order.getOiMessage().size(); i++) {
oiMsg += order.getOiMessage().get(i).get(0) + "/ ";
}
oiMsg = oiMsg.substring(0, oiMsg.lastIndexOf("/"));
order.setOiMsg(oiMsg);
orderInfoMapper.insertOrderInfo(order);
for (int i = 0; i < order.getOdList().size(); i++) {
if (order.getOdList().get(i) != null) {
od = order.getOdList().get(i);
od.setOiNum(order.getOiNum());
orderdetailsMapper.insertOrderDetails(od);
}
}
webSockethHandler.sendNotificatonToVenue(order.getViNum(), order.getOiNum());
rMap.put("result", "true");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
return rMap;
}
and it's the transaction aop class
#Configuration
#EnableAspectJAutoProxy
#EnableTransactionManagement
#Slf4j
public class TransactionAOP {
#Resource
private DataSourceTransactionManager dstm;
#Bean
#ConfigurationProperties(prefix="spring.datasource.hikari")
public DataSource getDS() {
return DataSourceBuilder.create().build();
}
#Bean
public DataSourceTransactionManager txManager() {
return new DataSourceTransactionManager(getDS());
}
#Bean
public TransactionInterceptor txInterceptor() {
log.debug("transaction starts...");
TransactionInterceptor txInterceptor = new TransactionInterceptor();
Properties prop = new Properties();
List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
rollbackRules.add(new RollbackRuleAttribute(Exception.class));
DefaultTransactionAttribute readOnly = new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED);
readOnly.setReadOnly(true);
readOnly.setTimeout(30);
RuleBasedTransactionAttribute update = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED,rollbackRules);
update.setTimeout(30);
prop.setProperty("select*", readOnly.toString());
prop.setProperty("get*", readOnly.toString());
prop.setProperty("find*", readOnly.toString());
prop.setProperty("search*", readOnly.toString());
prop.setProperty("count*", readOnly.toString());
prop.setProperty("*", update.toString());
txInterceptor.setTransactionAttributes(prop);
txInterceptor.setTransactionManager(dstm);
return txInterceptor;
}
#Bean
public Advisor txAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* com.grabit.bdi.service..*ServiceImpl.*(..))");
return new DefaultPointcutAdvisor(pointcut, txInterceptor());
}
}
thanks for your time in advance!
Could you try using the following instead?
#Transactional(rollbackFor = [Exception.class])
I thought I read somewhere that the API requires an array of Exception types to be stipulated in the attribute value.
My purpose - create test for DAO layer. My Hibernate config has datasourse specified throught JNDI. Also I use Jboss 5.1 so transaction lookup is necessary.
<property name="hibernate.connection.datasource">java:jdbc/MysqlDS</property>
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
<property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</property>
To make test I need bind these things. Todo this I create class util to bind. Full code below
public class RegisteringJNDIWithDataSource {
public static final String JNDI_MY_DS = "java:jdbc/MysqlDS";
private static final String MYSQL_USER = "user";
private static final String MYSQL_PASS = "pass";
private static final String MYSQL_HOST = "localhost";
public static String CTX_INITIAL_CONTEXT_FACTORY = "org.jnp.interfaces.NamingContextFactory";
public static String CTX_URL_PKG_RPEFIXES = "org.jboss.naming";
private void startRegistry() throws NamingException, RemoteException {
System.out.println(LocateRegistry.getRegistry());
Registry reg = LocateRegistry.createRegistry(1099);
NamingServer server = new NamingServer();
NamingContext.setLocal(server);
System.out.println("RMI registry Stared.");
}
public InitialContext createInitialContextContext() throws NamingException {
System.setProperty(Context.URL_PKG_PREFIXES, CTX_URL_PKG_RPEFIXES);
System.setProperty(Context.INITIAL_CONTEXT_FACTORY, CTX_INITIAL_CONTEXT_FACTORY);
InitialContext initialContextcontext = new InitialContext();
return initialContextcontext;
}
/**
* Registry the following JNDIs
*
* #throws RemoteException
* #throws NamingException
*/
public void registrate() throws RemoteException, NamingException {
startRegistry();
InitialContext ic;
ic = createInitialContextContext();
String[] cxts = JNDI_MY_DS.split("/");
String inCxt = cxts[0];
createSubcontext(ic, inCxt);
for (int i = 1; i < cxts.length - 1; i++) {
// if the data source name is like java:/comp/mysqldatasource
// this takes care of creating subcontexts in jndi
inCxt = inCxt + "/" + cxts[i];
createSubcontext(ic, inCxt);
}
ic.rebind(JNDI_MY_DS, createMysqlDataSource("db_name"));
// the following requires JBoss dependent class. May be sth can be done to generalize this
TransactionManager tm = new CustomTXNManager();
ic.bind("java:/TransactionManager", tm);
UserTransaction ut = new CustomUserTransaction();
ic.bind("UserTransaction", ut);
}
private static Context createSubcontext(Context ctx, String cxtName) throws NamingException {
System.out.println(" creating subcontext " + cxtName);
Context subctx = ctx;
Name name = ctx.getNameParser("").parse(cxtName);
for (int pos = 0; pos < name.size(); pos++) {
String ctxName = name.get(pos);
try {
subctx = (Context) ctx.lookup(ctxName);
} catch (NameNotFoundException e) {
subctx = ctx.createSubcontext(ctxName);
}
// The current subctx will be the ctx for the next name component
ctx = subctx;
}
return subctx;
}
public void unregistrate() throws NamingException {
InitialContext context;
context = createInitialContextContext();
context.unbind(JNDI_MY_DS);
}
private MysqlConnectionPoolDataSource createMysqlDataSource(String database) throws NamingException {
MysqlConnectionPoolDataSource dataSource;
dataSource = new MysqlConnectionPoolDataSource();
dataSource.setUser(MYSQL_USER);
dataSource.setPassword(MYSQL_PASS);
dataSource.setServerName(MYSQL_HOST);
dataSource.setPort(3306);
dataSource.setDatabaseName(database);
return dataSource;
}
public static void main(String args[]) {
RegisteringJNDIWithDataSource dataSource = new RegisteringJNDIWithDataSource();
try {
dataSource.registrate();
} catch (RemoteException ex) {
ex.printStackTrace();
} catch (NamingException ex) {
ex.printStackTrace();
}
}
public static class CustomTXNManager extends TransactionManagerImple implements Serializable {
private static final long serialVersionUID = 1L;
public CustomTXNManager() {
}
}
public static class CustomUserTransaction extends UserTransactionImple implements Serializable {
private static final long serialVersionUID = 1L;
public CustomUserTransaction() {
}
}
}
All works fine if call from console. But when I call this from JUnit I got exception.
#Test
public void test() throws RemoteException, NamingException {
RegisteringJNDIWithDataSource j = new RegisteringJNDIWithDataSource();
j.registrate();
}
javax.naming.OperationNotSupportedException
at com.sun.jndi.rmi.registry.RegistryContext.createSubcontext(RegistryContext.java:230)
at javax.naming.InitialContext.createSubcontext(InitialContext.java:464)