Hi Thiago, I don't believe I"m doing anything out of the ordinary or rather
anything different than I've ever done on any other project. Please take a
look at the code below and see if you notice anything that stands out.
Thanks in advance.
My usage.
*SupportContract*.tml
<t:form t:id="form" class="form-horizontal">
<t:errors/>
<t:AjaxFormLoop t:id="supportContract"
source="property.companyContracts" value="companyContract"
addRow="block:addRowContract" encoder="encoderContract" show="show">
<div class="form-group">
<t:label for="serviceType" class="col-sm-2 control-label"/>
<div class="col-sm-8">
<t:Select t:id="serviceType"
value="companyContract.supportContract" model="supportContractModel"
t:secure="literal:NEVER" blankOption="always" blankLabel="literal:Select
Service" class="form-control input-sm"/>
</div>
</div>
<div t:type="if" test="companyContract.id" class="form-group">
<div class="col-sm-offset-2 col-sm-8">
<div
class="float-right"><t:removerowlink>remove</t:removerowlink></div>
</div>
</div>
</t:AjaxFormLoop>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-8">
<t:Submit value="Save" class="btn btn-primary"/>
<t:PageLink page="index" class="btn">Cancel</t:PageLink>
</div>
</div>
</t:form>
SupportContract.java
@RequiresUser
public class *SupportContract* {
@Component(id = "form")
private Form form;
private CompanyContract companyContract;
@Inject
private Session session;
@Property
private Company property;
@Inject
private CrudServiceDAO crudServiceDAO;
@Inject
private SelectModelFactory selectModelFactory;
@Inject
private Request request;
private EventContext eventContext;
private boolean formSubmit;
public Class<?> onActivate(EventContext eventContext) {
formSubmit = false;
try {
if (!request.isXHR()) {
Integer id = eventContext.get(Integer.class, 0);
property = (Company) session.get(Company.class, id);
if(property == null) {
property = new Company();
}
}
this.eventContext = eventContext;
} catch (Exception ex) {
return Index.class;
}
return null;
}
public Object onPassivate() {
return eventContext.toStrings();
}
void onPrepareForSubmit() {
formSubmit = true;
}
void onValidateFromForm() {
if(companyContract != null && companyContract.getSupportContract()
== null) {
form.recordError("Fail");
}
}
@CommitAfter
void onSuccess() {
session.saveOrUpdate(property);
}
CompanyContract onAddRow() {
return new CompanyContract();
}
public CompanyContract getCompanyContract() {
return companyContract;
}
public void setCompanyContract(CompanyContract companyContract) {
this.companyContract = companyContract;
if(formSubmit) {
property.getCompanyContracts().add(companyContract);
}
}
@SuppressWarnings("unchecked")
public ValueEncoder getEncoderContract() {
return new ValueEncoder<CompanyContract>() {
@Override
public String toClient(CompanyContract value) {
Integer id = value.getId();
return id != null ? id.toString() : null;
}
@Override
public CompanyContract toValue(String toValue) {
if(toValue != null) {
Integer id = Integer.parseInt(toValue);
return (CompanyContract)
session.get(CompanyContract.class, id);
}
return new CompanyContract(property);
}
};
}
public SelectModel getSupportContractModel() {
List<SupportContract> supportContracts =
session.criteriaQuery(SupportContract.class).list()
return selectModelFactory.create(supportContracts, "name");
}
}
Company.class Entity (I use property variable)
@Entity
@Table(name = "company")
@Indexed
@AnalyzerDef(name = "customanalyzer",
tokenizer
= @TokenizerDef(factory = StandardTokenizerFactory.class),
filters = {
@TokenFilterDef(factory = LowerCaseFilterFactory.class),})
public class *Company* extends BaseEntity {
@OneToMany(mappedBy = "company", cascade = CascadeType.ALL,
orphanRemoval = true)
private List<CompanyContract> companyContracts;
public List<CompanyContract> getCompanyContracts() {
if (companyContracts == null) {
companyContracts = new ArrayList<>();
}
return companyContracts;
}
public void setCompanyContracts(List<CompanyContract> companyContracts)
{
this.companyContracts = companyContracts;
}
}
CompanyContact.class Entity
@Entity
public class *CompanyContract* extends BaseEntity {
@Validate("required")
@ManyToOne
@JoinColumn(name = "support_contract_id", nullable = false)
private SupportContract supportContract;
@Validate("required")
@ManyToOne
@JoinColumn(name = "company_id", nullable = false)
private Company company;
public CompanyContract() {
}
public CompanyContract(Company company) {
this.company = company;
}
public void setSupportContract(SupportContract supportContract) {
this.supportContract = supportContract;
}
public SupportContract getSupportContract() {
return supportContract;
}
public void setSupportContract(SupportContract supportContract) {
this.supportContract = supportContract;
}
}
@Entity
public class *SupportContract* extends BaseEntity {
@Column(nullable = false, length = 255)
@Validate("maxlength=255")
private String name;
@OneToMany(mappedBy = "supportContract")
private List<CompanyContract> companyContracts;
public SupportContract() {
}
public List<CompanyContract> getCompanyContracts() {
return companyContracts;
}
public void setCompanyContracts(List<CompanyContract> companyContracts)
{
this.companyContracts = companyContracts;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
*Hibernate.cfg.xml*
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate
Configuration DTD 3.0//EN" "
http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property
name="hibernate.connection.datasource">jdbc/domain</property>
<!-- <property
name="hibernate.connection.datasource">java:comp/env/jdbc/domain</property>-->
<property name="hbm2ddl.auto">validate</property>
<property
name="hibernate.search.default.directory_provider">filesystem</property>
<property
name="hibernate.search.default.indexBase">/users/george/Documents/indexes
</property>
<property name="hibernate.format_sql">false</property>
<property name="hibernate.show_sql">true</property>
</session-factory>
</hibernate-configuration>
*public class AppModule {*
private static final String EXCEPTION_HANDLE_METHOD_NAME =
"handleRequestException";
// TODO: Replace with true value
public static final String APP_ENV = "APP_ENV";
public static void bind(ServiceBinder binder) {
try {
ClassLoader contextClassLoader =
Thread.currentThread().getContextClassLoader();
List<Class<?>> daos =
PackageEnumerator.getClassesForPackage("com.communication.mydeepblue.dao");
for (Class<?> dao : daos) {
String pkg = dao.getPackage().getName();
String cls = dao.getSimpleName();
try {
Class impl = contextClassLoader.loadClass(pkg +
".impl." + cls + "Impl");
binder.bind(dao, impl);
} catch (ClassNotFoundException e) {
// Ignore, we just won't bind that class.
}
}
} catch (ClassNotFoundException e) {
java.util.logging.Logger.getLogger(AppModule.class.getName()).log(Level.SEVERE,
"AppModule error binding: ", e);
}
//Services
binder.bind(UserProfileService.class, UserProfileServiceImpl.class);
binder.bind(SearchService.class, SearchServiceImpl.class);
binder.bind(ProductionExceptionHandlerServiceImpl.class);
binder.bind(SchedulerService.class, SchedulerServiceImpl.class);
binder.bind(FileAttachmentService.class,
FileAttachmentServiceImpl.class);
binder.bind(RemoveRowFromAddRow.class,
RemoveRowFromAddRowImpl.class);
binder.bind(ProductionExceptionHandlerService.class,
ProductionExceptionHandlerServiceImpl.class);
binder.bind(KayakoWebService.class, KayakoWebServiceImpl.class);
binder.bind(CompanyResourceImpl.class, CompanyResourceImpl.class);
binder.bind(JerseyClientPost.class, JerseyClientPostImpl.class);
binder.bind(RoleManagerService.class, RoleManagerServiceImpl.class);
}
public static void contributeFactoryDefaults(
MappedConfiguration<String, Object> configuration) {
// The application version is incorprated into URLs for most
assets. Web
// browsers will cache assets because of the far future expires
header.
// If existing assets change (or if the Tapestry version changes)
you
// should also change this number, to force the browser to download
new
// versions. This overrides Tapesty's default (a random hexadecimal
// number), but may be further overriden by DevelopmentModule or
QaModule
// by adding the same key in the contributeApplicationDefaults
method.
configuration.override(SymbolConstants.APPLICATION_VERSION,
"2.0-SNAPSHOT");
configuration.override(SymbolConstants.PRODUCTION_MODE, false);
}
public static void contributeApplicationDefaults(
MappedConfiguration<String, Object> configuration) {
// Contributions to ApplicationDefaults will override any
contributions to
// FactoryDefaults (with the same key). Here we're restricting the
supported
// locales to just "en" (English). As you add localised message
catalogs and other assets,
// you can extend this list of locales (it's a comma separated
series of locale names;
// the first locale name is the default when there's no reasonable
match).
configuration.add(SymbolConstants.SUPPORTED_LOCALES, "en");
}
/**
* Use annotation or method naming convention:
* <code>contributeApplicationDefaults</code>
*/
@Contribute(SymbolProvider.class)
@ApplicationDefaults
public static void setupEnvironment(MappedConfiguration<String, Object>
configuration) {
configuration.add(SymbolConstants.JAVASCRIPT_INFRASTRUCTURE_PROVIDER,
"jquery");
configuration.add(SymbolConstants.HMAC_PASSPHRASE, "mydeepblue");
// configuration.add(SymbolConstants.MINIFICATION_ENABLED, true);
// Tynamo tapestry-security configuration
configuration.add(SecuritySymbols.LOGIN_URL, "/login");
configuration.add(SecuritySymbols.UNAUTHORIZED_URL, "/restricted");
//
ProductionMode.getInstance().setIsProduction(!"DEV".equals(System.getenv(APP_ENV)));
}
/*
// This will override the bundled bootstrap version and will compile
it at runtime
@Contribute(JavaScriptStack.class)
@Core
public static void
overrideBootstrapCSS(OrderedConfiguration<StackExtension> configuration)
{
configuration.override("bootstrap.css",
new StackExtension(StackExtensionType.STYLESHEET,
"context:mybootstrap/css/bootstrap.css"), "before:tapestry.css");
}
*/
/**
* This is a service definition, the service will be named
"TimingFilter".
* The interface, RequestFilter, is used within the RequestHandler
service
* pipeline, which is built from the RequestHandler service
configuration.
* Tapestry IoC is responsible for passing in an appropriate Logger
* instance. Requests for static resources are handled at a higher
level, so
* this filter will only be invoked for Tapestry related requests.
* <p/>
* <p/>
* Service builder methods are useful when the implementation is inline
as
* an inner class (as here) or require some other kind of special
* initialization. In most cases, use the static bind() method instead.
* <p/>
* <p/>
* If this method was named "build", then the service id would be taken
from
* the service interface and would be "RequestFilter". Since Tapestry
* already defines a service named "RequestFilter" we use an explicit
* service id that we can reference inside the contribution method.
*/
public RequestFilter buildTimingFilter(final Logger log) {
return new RequestFilter() {
public boolean service(Request request, Response response,
RequestHandler handler)
throws IOException {
long startTime = System.currentTimeMillis();
try {
// The responsibility of a filter is to invoke the
corresponding method
// in the handler. When you chain multiple filters
together, each filter
// received a handler that is a bridge to the next
filter.
return handler.service(request, response);
}
finally {
long elapsed = System.currentTimeMillis() - startTime;
log.info(String.format("Request time: %d ms", elapsed));
}
}
};
}
/**
* This is a contribution to the RequestHandler service configuration.
This
* is how we extend Tapestry using the timing filter. A common use for
this
* kind of filter is transaction management or security. The @Local
* annotation selects the desired service by type, but only from the
same
* module. Without @Local, there would be an error due to the other
* service(s) that implement RequestFilter (defined in other modules).
*/
public void
contributeRequestHandler(OrderedConfiguration<RequestFilter> configuration,
@Local RequestFilter filter) {
// Each contribution to an ordered configuration has a name, When
necessary, you may
// set constraints to precisely control the invocation order of the
contributed filter
// within the pipeline.
configuration.add("Timing", filter);
}
/**
* Contributions to the RESTeasy main Application, insert all your
RESTeasy
* singletons services here.
*/
@Contribute(Application.class)
public static void configureRestResources(Configuration<Object>
singletons, CompanyResource companyResource) {
singletons.add(companyResource);
}
@Startup
public static void initApplication(SchedulerService scheduler) {
scheduler.init();
}
public static void
contributeHibernateSessionSource(OrderedConfiguration<HibernateConfigurer>
configuration) {
configuration.addInstance("DeepBlue",
DeepBlueHibernateConfigurer.class);
}
public static void contributeWebSecurityManager(Configuration<Realm>
configuration, @Autobuild DeepBlueRealm realm) {
configuration.add(realm);
}
@Match("*DAO")
public static void adviseTransactions(HibernateTransactionAdvisor
advisor, MethodAdviceReceiver receiver) {
advisor.addTransactionCommitAdvice(receiver);
}
public static void
contributeResteasyPackageManager(org.apache.tapestry5.ioc.Configuration<String>
configuration) {
configuration.add("org.tynamo.resteasy.ws");
}
@Scope(ScopeConstants.PERTHREAD)
public static FullTextSession
buildFullTextSession(HibernateSessionManager sessionManager) {
return Search.getFullTextSession(sessionManager.getSession());
}
@Startup
public static void initApplication(FullTextSession fullTextSession)
throws InterruptedException {
fullTextSession.createIndexer().startAndWait();
}
}
*DeepBlueHibernateConfigurer.class *
public class DeepBlueHibernateConfigurer implements HibernateConfigurer {
public void configure(Configuration configuration) {
configuration.setNamingStrategy(ImprovedNamingStrategy.INSTANCE);
}
}
On Thu, Dec 19, 2013 at 5:57 AM, Thiago H de Paula Figueiredo <
[email protected]> wrote:
> On Thu, 19 Dec 2013 05:27:19 -0200, George Christman <
> [email protected]> wrote:
>
> While trying to submit a new record with blankOption="always" and
>> t:secure="literal:NEVER" I'm finding when my getModel method is
>> called, the query used to rebuild my select model attempts to commit
>> my object model to the database resulting in a database constraint
>> violation exception rather than throw back a validation error.
>>
>
> Are you sure the code that triggers the database insertion isn't yours?
>
> This looks more like bad usage of Hibernate in your side than a Tapestry
> error, but without all the corresponding code there's no way to be sure.
>
>
> Now I'm not sure if this really matters, but I am using this select
>> component within an ajaxformloop.
>>
>
> Maybe. You didn't post the code of your AjaxFormLoop event handler methods
> nor the ValueEncoder you're using (if it's not the one automatically
> provided by tapestry-hibernate).
>
> --
> Thiago H. de Paula Figueiredo
> Tapestry, Java and Hibernate consultant and developer
> http://machina.com.br
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [email protected]
> For additional commands, e-mail: [email protected]
>
>
--
George Christman
www.CarDaddy.com
P.O. Box 735
Johnstown, New York