/* * Copyright (c) 2010. Axon Auction Example * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.fuin.auction.command.server.base; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import javax.inject.Named; import org.fuin.auction.command.server.domain.CategoryNameAlreadyExistException; import org.fuin.auction.command.server.domain.UserEmailAlreadyExistsException; import org.fuin.auction.command.server.domain.UserNameAlreadyExistsException; import org.fuin.auction.command.server.domain.UserNameEmailCombinationAlreadyExistsException; import org.fuin.auction.command.server.utils.AbstractJdbcHelper; import org.fuin.auction.common.CategoryName; import org.fuin.objects4j.EmailAddress; import org.fuin.objects4j.UserName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Pure JDBC constraint service (Apache Derby!). Could be done more nice * (database independent for example...) but it's just to show that there is no * need that a "full-blown" Hibernate or JPA here... */ @Named public final class ConstraintSetJdbc extends AbstractJdbcHelper implements ConstraintSet { private static final Logger LOG = LoggerFactory.getLogger(ConstraintSetJdbc.class); /** * Default constructor. */ public ConstraintSetJdbc() { super(ConstraintSetJdbc.class, "/jdbc.properties"); } @Override public final void add(final UserName userName, final EmailAddress email) throws UserNameEmailCombinationAlreadyExistsException, UserNameAlreadyExistsException, UserEmailAlreadyExistsException { try { if (!insert(userName, email)) { final String userNameStr = userName.toString(); final String emailStr = email.toString(); final UserNameEmail row = select(userName, email); if (row.getUserName().equals(userNameStr)) { if (row.getEmail().equals(emailStr)) { throw new UserNameEmailCombinationAlreadyExistsException(); } throw new UserNameAlreadyExistsException(); } else { if (row.getEmail().equals(emailStr)) { throw new UserEmailAlreadyExistsException(); } // This should never happen because it doesn't fit to there // where clause. throw new RuntimeException("Unexpected result - Requested: userName='" + userName + "', email='" + email + "' / Returned: userName='" + row.getUserName() + "', email='" + row.getEmail() + "'"); } } } catch (final SQLException ex) { final String message = "Error adding userName/email constraint!"; LOG.error(message + " [SQLState=" + ex.getSQLState() + ", ErrorCode=" + ex.getErrorCode() + "]", ex); throw new RuntimeException(message); } } @Override public final void remove(final UserName userName, final EmailAddress email) { executeUpdateSilent( "delete from COMMANDSERVER.USERNAME_EMAIL where USER_NAME=? and EMAIL=?", userName .toString(), email.toString()); } @Override public final void add(final CategoryName categoryName) throws CategoryNameAlreadyExistException { try { executeUpdate("insert into COMMANDSERVER.CATEGORY_NAMES (NAME) values (?)", categoryName.toString()); } catch (final SQLException ex) { // Duplicate key value in primary key if (!ex.getSQLState().equals("23505")) { throw new RuntimeException(ex); } throw new CategoryNameAlreadyExistException(); } } @Override public final void remove(final CategoryName categoryName) { executeUpdateSilent("delete from COMMANDSERVER.CATEGORY_NAMES where NAME=?", categoryName .toString()); } /** * Tries to insert the userid/email combination and wraps a * "duplicate primary key" exception into a <code>false</code> return value. * * @param userName * User's unique name. * @param email * User's email address. * * @return If the combination was inserted <code>true</code> else * <code>false</code> ("duplicate primary key"). * * @throws SQLException * Other error than "duplicate primary key". */ private boolean insert(final UserName userName, final EmailAddress email) throws SQLException { try { executeUpdate("insert into COMMANDSERVER.USERNAME_EMAIL (USER_NAME, EMAIL) " + "values (?, ?)", userName.toString(), email.toString()); return true; } catch (final SQLException ex) { // Duplicate key value in primary key if (!ex.getSQLState().equals("23505")) { throw ex; } return false; } } /** * Selects user name and email based on user name or email address. * * @param userName * User's unique name to find. * @param email * Email address to find. * * @return User name and email. */ private UserNameEmail select(final UserName userName, final EmailAddress email) { final List<UserNameEmail> list = selectSilent( "select * from COMMANDSERVER.USERNAME_EMAIL where USER_NAME=? or EMAIL=?", new UserNameEmailCreator(), userName.toString(), email.toString()); if (list.size() == 0) { throw new IllegalStateException("Neither user name '" + userName + "' nor email '" + email + "' found!"); } else if (list.size() > 1) { throw new IllegalStateException("Found more than one entry for user name '" + userName + "' or email '" + email + "'!"); } return list.get(0); } /** * Helper class to return result. */ private static final class UserNameEmail { private final String userName; private final String email; /** * Constructor with user name and email. * * @param userName * User name. * @param email * Email address. */ public UserNameEmail(final String userName, final String email) { super(); this.userName = userName; this.email = email; } /** * Returns the user name. * * @return user name. */ public String getUserName() { return userName; } /** * Returns the email. * * @return Email address. */ public String getEmail() { return email; } } /** * Creates {@link UserNameEmail} instances from a JDBC result set. */ private static final class UserNameEmailCreator implements Creator<UserNameEmail> { @Override public final UserNameEmail create(final ResultSet rs) throws SQLException { return new UserNameEmail(rs.getString("USER_NAME"), rs.getString("EMAIL")); } } }