I had the following code, which is responsible for assigning roles and groups to users.
private void override(List<Assignment> assignments) {
removeAll();
addMultiple(assignments);
}
protected void removeAll() {
removeAllRoles();
removeAllGroups();
}
private void removeAllGroups() {
Iterator<String> userGroups = user.getParentGroups(false);
while (userGroups.hasNext()) {
UMHelper.removeUserFromGroup(user.getUniqueID(), userGroups.next());
}
}
private void addMultiple(List<Assignment> assignments) {
for (Assignment assignment : assignments) {
add(assignment);
}
}
public static void addUserToGroup(String userId, String groupId) {
try {
SimpleLogger.log(Severity.INFO, Category.APPLICATIONS, loc, null, "Trying to add user " + userId + " to group " + groupId);
groupFactory.addUserToGroup(userId, groupId);
SimpleLogger.log(Severity.INFO, Category.APPLICATIONS, loc, null, "Success");
} catch (UMException e) {
SimpleLogger.traceThrowable(Severity.ERROR, loc, "Addition failed", e);
}
}
I hope the logic is pretty clear. Most of the code is iteration over collections. Adding a user to role or group can cause exception, which I report in log.
Since I find it not good to suppress exceptions and because a client calling override method should know the result of assigment, I rewrote the code adding exception handling. The execution should continue, even if some assignments failed.
private void override(List<Assignment> assignments) {
SimpleLogger.log(Severity.INFO, Category.APPLICATIONS, loc, null, "Override was started with " + assignments.size() + " assignments");
try {
removeAll();
} catch (UMException e) {
SimpleLogger.log(Severity.INFO, Category.APPLICATIONS, loc, null, "Removing all existing elements failed");
}
try {
addMultiple(assignments);
} catch (UMException e) {
SimpleLogger.log(Severity.INFO, Category.APPLICATIONS, loc, null, "Adding new elements failed");
}
}
protected void removeAll() throws UMException {
boolean successfulRemoval = true;
try {
removeAllRoles();
} catch (UMException e) {
successfulRemoval = false;
}
try {
removeAllGroups();
} catch (UMException e) {
successfulRemoval = false;
}
if (!successfulRemoval){
throw new UMException("Not all user elements could be removed");
}
}
private void removeAllGroups() throws UMException {
boolean removeSuccessful = true;
Iterator<String> userGroups = user.getParentGroups(false);
while (userGroups.hasNext()) {
try {
UMHelper.removeUserFromGroup(user.getUniqueID(), userGroups.next());
} catch (UMException e) {
removeSuccessful = false;
}
}
if (!removeSuccessful) {
throw new UMException("Not all user groups could be removed");
}
}
private void addMultiple(List<Assignment> assignments) throws UMException {
boolean additionSuccessful = true;
for (Assignment assignment : assignments) {
try {
add(assignment);
} catch (UMException e) {
additionSuccessful = false;
}
}
if (!additionSuccessful) {
throw new UMException("Addition of new rights failed");
}
}
public static void addUserToGroup(String userId, String groupId) throws UMException {
SimpleLogger.log(Severity.INFO, Category.APPLICATIONS, loc, null, "Trying to add user " + userId + " to group " + groupId);
groupFactory.addUserToGroup(userId, groupId);
SimpleLogger.log(Severity.INFO, Category.APPLICATIONS, loc, null, "Success");
}
Now the code got 3 times bigger and not as clear as it was. If I just had to stop execution after first assignment failed, the code would have been easier, but that's the requirement. Do I handle exceptions wrong or is there a way to improve the code?
In this scenario I would change all these methods from throwing exceptions to
returning a boolean value which indicates if they did their job successfully or not.
If you have control over these methods and can do this change, I think that's better
suited for your scenario.
With a little code reorganization, that is, all removals/additions/etc are in a single transaction, the code can be made clearer, as in, for instance:
String failmsg = null;
// tx is some transaction object
tx.start();
try {
failmsg = "user removal failed";
tx.removeUsers();
failmsg = "group removal failed";
tx.removeGroups();
failmsg = "new additions failed";
tx.addNew();
tx.commit();
} catch (UMException e) {
tx.rollback();
log(failmsg);
} finally {
tx.close();
}
Related
I'm trying to make simple telegram bot on Java.
The question is: how can I receive messages in a loop, when the user typed /start? I have already some
#Override
public void onUpdateReceived(Update update) {
Message msg = update.getMessage();
String txt = msg.getText();
if (txt.equals("/start")) {
sendMsg(msg, "Привет, меня зовут бот " + name + "!");
showHelp(msg);
run(msg, update);
} else if (txt.equals("/help")) {
showHelp(msg);
}
}
Here's showhelp:
private void showHelp(Message msg) {
try {
String inAbout = ReadFile.readFileInString(this.about);
sendMsg(msg, inAbout);
} catch (Exception ex) {
ex.printStackTrace();
}
}
sendMsg:
private void sendMsg(Message msg, String text) {
SendMessage s = new SendMessage();
s.setChatId(msg.getChatId());
s.setText(text);
try {
execute(s);
} catch (TelegramApiException e) {
e.printStackTrace();
}
}
In Run I want to read questions from data and wait for users answer, check if correct and do it in loop. In the end show how many he answered correct.
public void run(Message msg, Update update) {
try {
List<String> data = ReadFile.readFileInList(this.getData());
List<String> dataAnswers = ReadFile.readFileInList(this.answers);
this.sizeOfAnswers = data.size();
for (int i = 0; i < data.size(); i++) {
String line = data.get(i);
sendMsg(msg, line);
String inAnswer = update.getMessage().getText();
String rAns = dataAnswers.get(i);
boolean flag = checkAnswer(inAnswer, rAns);
if (flag) {
this.currentUser.incrementScore();
}
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
String finalString = "Поздравляю, ты ответил на " + this.currentUser.getScore() + "/" + this.sizeOfAnswers
+ " вопросов!";
sendMsg(msg, finalString);
}
}
Also here is maybe some multi user problems. How should I do it? Now it's showing all questions in one second without waiting for an answer.
How it's working now
A project source code has a Java method for SQL handling. The method does work, but it uses a questionable workaround: try-catch block at the very end of the method for normal execution. What is the correct way to implement it?
public void run() {
if (running) {
return;
}
running = true;
while(null == Common.server || null == Common.database || !ConnectionsPool.isInitialized()) {
// Wait until the database is set before continuing...
try {
Thread.sleep(1000);
}
catch(Exception ex) {}
}
while(running) {
final Connections cs = ConnectionsPool.getConnections();
Connection c = null;
while(!entries.isEmpty()) {
if (null == c) {
c = cs.getConnection();
}
SQLLogEntry entry = entries.remove();
if (null != entry) {
try {
write(entry, c); //find usages
}
catch (SQLException ex) {
writeLogFile("Could not write entry to SQL", ex);
}
}
}
if (null != c) {
try {
c.commit();
}
catch (SQLException ex) {
writeLogFile("Could commit to SQL", ex);
try {
c.rollback();
}
catch (SQLException ex1) {
}
// log
final StringWriter err = new StringWriter();
ex.printStackTrace(new PrintWriter(err));
EditorTransactionUtil.writeLogFile(err.toString());
// for user
final String msg = "Exception: " + EditorUtil.getErrorMessage(ex.getMessage());
try {
SwingUtilities.invokeAndWait(() -> {
JOptionPane.showMessageDialog(null, msg);
});
}
catch (Throwable ex1) {
}
}
finally {
cs.returnConnection(c);
}
c = null;
}
synchronized(entries) {
try {
entries.wait(1000);
}
catch (InterruptedException ex) {
// This is a workaround to process this loop...
}
}
}
writeLogFile("SQLMsgLogger run loop stopping...");
}
Problems with this code start here.
If(running) return;
running=true;
This is clearly an attempt to make sure that only one thread executes. This is a wrong way to check concurrency. Second tread might kick in right when if check ended, but assignment didn't start yet. You need to use syncronizible interface.
As for the disposed try catch block - as Konrad pointed out it will not be executed without Thread.interrupt() call. It might be dead code left from previous versions.
I have a very curious situation.
I'm trying to execute EJB's method and returns the result with JAX-RS
public Service readSingle(...) {
try {
service.query(...);
} catch (final NoResultException nre) {
throw new NotFoundException(...);
} catch (final NonUniqueResultException nure) {
throw new BadRequstException(...);
}
}
The query method requires some values and a BiFuction and a Function.
The actual call looks like this.
try {
return serviceService.<Service>query(
id,
ofNullable(matrixParameters.getFirst("onid"))
.map(Integer::parseInt).orElse(null),
ofNullable(matrixParameters.getFirst("tsid"))
.map(Integer::parseInt).orElse(null),
ofNullable(matrixParameters.getFirst("sid"))
.map(Integer::parseInt).orElse(null),
ofNullable(matrixParameters.getFirst("number"))
.map(Integer::parseInt).orElse(null),
ofNullable(matrixParameters.getFirst("programId"))
.orElse(null),
operatorId,
(builder, root) -> emptyList(),
TypedQuery::getSingleResult);
} catch (final NoResultException nre) {
throw new NotFoundException(
"no entity idnetified by " + serviceIdSegment.getPath()
+ " with " + matrixParameters.toString());
} catch (final NonUniqueResultException nure) {
throw new BadRequestException("multiple entities identified");
}
Ok I passed TypedQuery::getSingleResult and I expect NonUniqueResultException should be caught when it has to be thrown.
But Payara keep responding with 500 and the log shows that the NonUniqueResultException has never caught by the code.
I disabled my ExceptionMappers the the results are same.
Ok. I figured it out. I had to do this.
try {
// execute EJB
} catch (final EJBTransactionRolledbackException ejbtre) {
Exception leaf = ejbtre;
try {
for (Exception c;
(c = ((EJBException) leaf).getCausedByException()) != null;
leaf = c);
} catch (final ClassCastException cce) {
}
logger.severe("causedByException: " + leaf);
if (leaf instanceof NoResultException) {
throw new NotFoundException(
"no entity idnetified by " + serviceIdSegment.getPath()
+ " with " + matrixParameters.toString());
} else if (leaf instanceof NonUniqueResultException) {
throw new BadRequestException(
"multiple entities identified by "
+ serviceIdSegment.getPath()
+ " with " + matrixParameters.toString());
}
throw new InternalServerErrorException(ejbtre);
}
This is far nasty beyond I've expected. The EJB's method design is not good.
Is there any way to do this more simply?
Let me introduce one of my utility class I used to justify myself.
public final class EJBExceptions {
private static final Logger logger
= getLogger(EJBExceptions.class.getName());
public static Stream<Exception> causedByExceptions(EJBException ejbe) {
final Stream.Builder<Exception> builder = Stream.builder();
while (ejbe != null) {
final Exception causedByException = ejbe.getCausedByException();
if (causedByException != null) {
builder.add(causedByException);
} else {
break;
}
if (causedByException instanceof EJBException) {
ejbe = (EJBException) causedByException;
} else {
break;
}
}
return builder.build();
}
public static Optional<Exception> lastCausedByException(
final EJBException ejbe) {
return causedByExceptions(ejbe).reduce((first, second) -> second);
}
private EJBExceptions() {
super();
}
}
im trying to implement SQLGrammarException into my method.
This method show me column error, but i need to show what procedure the column with error from.
public static PersistenceMicrodataException dealHibernateException(Throwable e) {
e.printStackTrace();
Throwable t = ExceptionUtil.getCause(e);
return new PersistenceMicrodataException(t.getMessage(), t);
}
I try this:
public static PersistenceMicrodataException dealHibernateException(Throwable e) {
try {
Throwable t = ExceptionUtil.getCause(e);
} catch (Exception e) {
System.out.println(t.getMessage());
System.out.println(((SQLGrammarException) t).getSQLState());
System.out.println(((SQLGrammarException) t).getErrorCode());
System.out.println(t.getCause());
}
return new PersistenceMicrodataException(e.getMessage(), e);
}
Someone can help me with this?
I found solution!
public static PersistenceMicrodataException dealHibernateException(Throwable e) {
String concatError = ((SQLGrammarException) e).getSQL() + ((SQLGrammarException) e).getClass() + ((SQLGrammarException) e).getCause();
while (e != null) {
java.lang.System.out.println(concatError);
break;
}
Throwable t = ExceptionUtil.getCause(e);
return new PersistenceMicrodataException(concatError,t);
}
Eclipse give me that warning in the following code:
public int getTicket(int lotteryId, String player) {
try {
c = DriverManager.getConnection("jdbc:mysql://" + this.hostname + ":" + this.port + "/" + this.database, this.user, this.password);
int ticketNumber;
PreparedStatement p = c.prepareStatement(
"SELECT max(num_ticket) " +
"FROM loteria_tickets " +
"WHERE id_loteria = ?"
);
p.setInt(1, lotteryId);
ResultSet rs = p.executeQuery();
if (rs.next()) {
ticketNumber = rs.getInt(1);
} else {
ticketNumber = -1;
}
ticketNumber++;
p = c.prepareStatement(
"INSERT INTO loteria_tickets " +
"VALUES (?,?,?,?)");
p.setInt(1, lotteryId);
p.setInt(2, ticketNumber);
p.setString(3, player);
p.setDate(4, new java.sql.Date((new java.util.Date()).getTime()));
p.executeUpdate();
return ticketNumber;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (c != null) {
try {
c.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return -1;
}
}
What is wrong with my code?
remove return statement from it.
Final block is considered to be cleanup block, return is not generally expected in it.
The return from finally "overrides" further exception throwing.
public class App {
public static void main(String[] args) {
System.err.println(f());
}
public static int f() {
try {
throw new RuntimeException();
} finally {
return 1;
}
}
}
1
Generally a finally block should never have a return statement because it would overwrite other return-statements or Exceptions.
For further reading and more detailed answers to the backgrounds of it please see the question
Behaviour of return statement in catch and finally
With both return and throw statement in the finally bloc you will get the warning, for example, you will get the same warning with the following finally block:
...
}finally{
throw new RuntimeException("from finally!");
}
...
If you don't have any catch blocks, then your finally blocks have to be nested directly inside of each other. It's only catching an exception that allows your code to continue past the end of a try/catch/finally block. If you don't catch the exception, you can't have any code after a finally block!
You can see how this works with this example on Repl.it
Example Output
testing if 0 > 5 ?
try1
try2
finally3
catch1
finally2
After other finally
finally1
end of function
testing if 10 > 5 ?
try1
try2
try3
success
finally3
finally2
finally1
Code in example at Repl.it
class Main {
public static void main(String[] args) {
isGreaterThan5(0);
isGreaterThan5(10);
}
public static boolean isGreaterThan5(int a)
{
System.out.println();
System.out.println("testing if " + a + " > 5 ?");
try
{
System.out.println("try1");
try
{
System.out.println("try2");
try
{
if (a <= 5)
{
throw new RuntimeException("Problems!");
}
System.out.println("try3");
System.out.println("success");
return true;
}
finally
{
System.out.println("finally3");
}
}
catch (Exception e)
{
System.out.println("catch1");
}
finally
{
System.out.println("finally2");
}
System.out.println("After other finally");
}
catch (Exception e)
{
System.out.println("failed");
return false;
}
finally
{
System.out.println("finally1");
}
System.out.println("end of function");
return false;
}
}