Merge pull request #210 from Doha2012/master

move oauth module to reddit app
This commit is contained in:
Eugen 2015-05-13 16:21:43 +01:00
commit 0b03522131
49 changed files with 0 additions and 17568 deletions

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry including="**/*.java" kind="src" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry including="**/*.java" kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>spring-security-oauth</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.common.project.facet.core.builder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.springframework.ide.eclipse.core.springbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.validation.validationbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
<nature>org.springframework.ide.eclipse.core.springnature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
</natures>
</projectDescription>

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beansProjectDescription>
<version>1</version>
<pluginVersion><![CDATA[3.6.3.201411271034-RELEASE]]></pluginVersion>
<configSuffixes>
<configSuffix><![CDATA[xml]]></configSuffix>
</configSuffixes>
<enableImports><![CDATA[true]]></enableImports>
<configs>
</configs>
<autoconfigs>
</autoconfigs>
<configSets>
</configSets>
</beansProjectDescription>

View File

@ -1 +0,0 @@
web: java $JAVA_OPTS -jar target/dependency/webapp-runner.jar --port $PORT target/*.war

View File

@ -1,501 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.baeldung</groupId>
<artifactId>spring-security-oauth</artifactId>
<version>0.1-SNAPSHOT</version>
<name>spring-security-oauth</name>
<packaging>war</packaging>
<dependencies>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${org.springframework.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${org.springframework.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${org.springframework.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.0.6.RELEASE</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!-- web -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>${httpcore.version}</version>
</dependency>
<!-- thymeleaf -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity3</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
<!-- persistence -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring-data-jpa.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.4.01</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.19.0-GA</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
<scope>runtime</scope>
</dependency>
<!-- h2 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.187</version>
</dependency>
<!-- postgresql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1201-jdbc41</version>
</dependency>
<!-- web -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
<scope>runtime</scope>
</dependency>
<!-- apache mahout -->
<dependency>
<groupId>org.apache.mahout</groupId>
<artifactId>mahout-core</artifactId>
<version>0.9</version>
</dependency>
<!-- marshalling -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.8</version>
</dependency>
<!-- util -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<!-- <scope>runtime</scope> -->
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j.version}</version>
<!-- <scope>runtime</scope> --> <!-- some spring dependencies need to compile against jcl -->
</dependency>
<dependency> <!-- needed to bridge to slf4j for projects that use the log4j APIs directly -->
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>${org.slf4j.version}</version>
</dependency>
<!-- test scoped -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit-dep</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>${org.hamcrest.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>${org.hamcrest.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.restassured</groupId>
<artifactId>rest-assured</artifactId>
<version>2.4.0</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<finalName>spring-security-oauth</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin.version}</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
<excludes>
<exclude>**/*IntegrationTest.java</exclude>
<exclude>**/*LiveTest.java</exclude>
</excludes>
<systemPropertyVariables>
<!-- <provPersistenceTarget>h2</provPersistenceTarget> -->
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>${cargo-maven2-plugin.version}</version>
<configuration>
<wait>true</wait>
<container>
<containerId>jetty8x</containerId>
<type>embedded</type>
<systemProperties>
<!-- <provPersistenceTarget>cargo</provPersistenceTarget> -->
</systemProperties>
</container>
<configuration>
<properties>
<cargo.servlet.port>8080</cargo.servlet.port>
</properties>
</configuration>
</configuration>
</plugin>
<!-- webapp runner -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>copy</goal></goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.github.jsimone</groupId>
<artifactId>webapp-runner</artifactId>
<version>7.0.57.2</version>
<destFileName>webapp-runner.jar</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>integration</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<excludes>
<exclude>none</exclude>
</excludes>
<includes>
<include>**/*IntegrationTest.java</include>
<include>**/*LiveTest.java</include>
</includes>
</configuration>
</execution>
</executions>
<configuration>
<systemPropertyVariables>
<test.mime>json</test.mime>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<configuration>
<wait>false</wait>
</configuration>
<executions>
<execution>
<id>start-server</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-server</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<properties>
<!-- Spring -->
<org.springframework.version>4.1.6.RELEASE</org.springframework.version>
<org.springframework.security.version>3.2.7.RELEASE</org.springframework.security.version>
<!-- persistence -->
<hibernate.version>4.3.8.Final</hibernate.version>
<mysql-connector-java.version>5.1.35</mysql-connector-java.version>
<spring-data-jpa.version>1.7.1.RELEASE</spring-data-jpa.version>
<!-- marshalling -->
<jackson.version>2.5.1</jackson.version>
<!-- logging -->
<org.slf4j.version>1.7.12</org.slf4j.version>
<logback.version>1.1.3</logback.version>
<!-- various -->
<hibernate-validator.version>5.1.3.Final</hibernate-validator.version>
<!-- util -->
<guava.version>18.0</guava.version>
<commons-lang3.version>3.3.2</commons-lang3.version>
<!-- testing -->
<org.hamcrest.version>1.3</org.hamcrest.version>
<junit.version>4.11</junit.version>
<mockito.version>1.10.19</mockito.version>
<httpcore.version>4.4</httpcore.version>
<httpclient.version>4.4</httpclient.version>
<rest-assured.version>2.4.0</rest-assured.version>
<!-- Maven plugins -->
<maven-compiler-plugin.version>3.3</maven-compiler-plugin.version>
<maven-war-plugin.version>2.6</maven-war-plugin.version>
<maven-surefire-plugin.version>2.18.1</maven-surefire-plugin.version>
<cargo-maven2-plugin.version>1.4.12</cargo-maven2-plugin.version>
</properties>
</project>

View File

@ -1,114 +0,0 @@
package org.baeldung.config;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import java.util.TreeMap;
import org.springframework.http.HttpHeaders;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.oauth2.client.filter.state.DefaultStateKeyGenerator;
import org.springframework.security.oauth2.client.filter.state.StateKeyGenerator;
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.resource.UserApprovalRequiredException;
import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidRequestException;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
public class MyAuthorizationCodeAccessTokenProvider extends AuthorizationCodeAccessTokenProvider implements Serializable {
private static final long serialVersionUID = 3822611002661972274L;
private final StateKeyGenerator stateKeyGenerator = new DefaultStateKeyGenerator();
@Override
public OAuth2AccessToken obtainAccessToken(OAuth2ProtectedResourceDetails details, AccessTokenRequest request) throws UserRedirectRequiredException, UserApprovalRequiredException, AccessDeniedException, OAuth2AccessDeniedException {
final AuthorizationCodeResourceDetails resource = (AuthorizationCodeResourceDetails) details;
if (request.getAuthorizationCode() == null) {
if (request.getStateKey() == null) {
throw getRedirectForAuthorization(resource, request);
}
obtainAuthorizationCode(resource, request);
}
return retrieveToken(request, resource, getParametersForTokenRequest(resource, request), getHeadersForTokenRequest(request));
}
private HttpHeaders getHeadersForTokenRequest(AccessTokenRequest request) {
final HttpHeaders headers = new HttpHeaders();
return headers;
}
private MultiValueMap<String, String> getParametersForTokenRequest(AuthorizationCodeResourceDetails resource, AccessTokenRequest request) {
final MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
form.set("grant_type", "authorization_code");
form.set("code", request.getAuthorizationCode());
final Object preservedState = request.getPreservedState();
if (request.getStateKey() != null) {
if (preservedState == null) {
throw new InvalidRequestException("Possible CSRF detected - state parameter was present but no state could be found");
}
}
String redirectUri = null;
if (preservedState instanceof String) {
redirectUri = String.valueOf(preservedState);
} else {
redirectUri = resource.getRedirectUri(request);
}
if ((redirectUri != null) && !"NONE".equals(redirectUri)) {
form.set("redirect_uri", redirectUri);
}
return form;
}
private UserRedirectRequiredException getRedirectForAuthorization(AuthorizationCodeResourceDetails resource, AccessTokenRequest request) {
final TreeMap<String, String> requestParameters = new TreeMap<String, String>();
requestParameters.put("response_type", "code");
requestParameters.put("client_id", resource.getClientId());
requestParameters.put("duration", "permanent");
final String redirectUri = resource.getRedirectUri(request);
if (redirectUri != null) {
requestParameters.put("redirect_uri", redirectUri);
}
if (resource.isScoped()) {
final StringBuilder builder = new StringBuilder();
final List<String> scope = resource.getScope();
if (scope != null) {
final Iterator<String> scopeIt = scope.iterator();
while (scopeIt.hasNext()) {
builder.append(scopeIt.next());
if (scopeIt.hasNext()) {
builder.append(',');
}
}
}
requestParameters.put("scope", builder.toString());
}
final UserRedirectRequiredException redirectException = new UserRedirectRequiredException(resource.getUserAuthorizationUri(), requestParameters);
final String stateKey = stateKeyGenerator.generateKey(resource);
redirectException.setStateKey(stateKey);
request.setStateKey(stateKey);
redirectException.setStateToPreserve(redirectUri);
request.setPreservedState(redirectUri);
return redirectException;
}
}

View File

@ -1,75 +0,0 @@
package org.baeldung.config;
import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@PropertySource({ "classpath:persistence-${envTarget:dev}.properties" })
@ComponentScan({ "org.baeldung.persistence" })
@EnableJpaRepositories(basePackages = "org.baeldung.persistence.dao")
public class PersistenceJPAConfig {
@Autowired
private Environment env;
public PersistenceJPAConfig() {
super();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "org.baeldung.persistence.model" });
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
@Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.user"));
dataSource.setPassword(env.getProperty("jdbc.pass"));
return dataSource;
}
@Bean
public JpaTransactionManager transactionManager() {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
final Properties additionalProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto", "create-drop"));
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
return hibernateProperties;
}
}

View File

@ -1,47 +0,0 @@
package org.baeldung.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.anonymous().disable()
.csrf().disable()
.authorizeRequests()
.antMatchers("/home.html","/post","/postSchedule","/posts").hasRole("USER")
.and()
.httpBasic().authenticationEntryPoint(oauth2AuthenticationEntryPoint())
.and()
.logout()
.deleteCookies("JSESSIONID")
.logoutUrl("/logout")
.logoutSuccessUrl("/");
// @formatter:on
}
private LoginUrlAuthenticationEntryPoint oauth2AuthenticationEntryPoint() {
return new LoginUrlAuthenticationEntryPoint("/login");
}
}

View File

@ -1,44 +0,0 @@
package org.baeldung.config;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
public class ServletInitializer extends AbstractDispatcherServletInitializer {
@Override
protected WebApplicationContext createServletApplicationContext() {
final AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(PersistenceJPAConfig.class, WebConfig.class, SecurityConfig.class, ThymeleafConfig.class);
return context;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
@Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
servletContext.addListener(new SessionListener());
registerProxyFilter(servletContext, "oauth2ClientContextFilter");
registerProxyFilter(servletContext, "springSecurityFilterChain");
}
private void registerProxyFilter(ServletContext servletContext, String name) {
final DelegatingFilterProxy filter = new DelegatingFilterProxy(name);
filter.setContextAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher");
servletContext.addFilter(name, filter).addMappingForUrlPatterns(null, false, "/*");
}
}

View File

@ -1,24 +0,0 @@
package org.baeldung.config;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import org.baeldung.reddit.util.MyFeatures;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SessionListener implements HttpSessionListener {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void sessionCreated(HttpSessionEvent event) {
logger.info("==== Session is created ====");
event.getSession().setMaxInactiveInterval(60 * 60);
event.getSession().setAttribute("PREDICTION_FEATURE", MyFeatures.PREDICTION_FEATURE);
}
@Override
public void sessionDestroyed(HttpSessionEvent event) {
logger.info("==== Session is destroyed ====");
}
}

View File

@ -1,39 +0,0 @@
package org.baeldung.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.thymeleaf.extras.springsecurity3.dialect.SpringSecurityDialect;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.spring4.view.ThymeleafViewResolver;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
import org.thymeleaf.templateresolver.TemplateResolver;
@Configuration
public class ThymeleafConfig {
@Bean
public TemplateResolver templateResolver() {
final ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setPrefix("/WEB-INF/jsp/");
templateResolver.setSuffix(".jsp");
return templateResolver;
}
@Bean
public SpringTemplateEngine templateEngine() {
final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.addDialect(new SpringSecurityDialect());
return templateEngine;
}
@Bean
public ViewResolver viewResolver() {
final ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
return viewResolver;
}
}

View File

@ -1,161 +0,0 @@
package org.baeldung.config;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.annotation.PostConstruct;
import org.apache.commons.lang.StringUtils;
import org.baeldung.persistence.dao.PostRepository;
import org.baeldung.reddit.classifier.RedditClassifier;
import org.baeldung.reddit.util.MyFeatures;
import org.baeldung.reddit.util.UserAgentInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.AccessTokenProvider;
import org.springframework.security.oauth2.client.token.AccessTokenProviderChain;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.client.token.grant.implicit.ImplicitAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordAccessTokenProvider;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
@EnableScheduling
@EnableAsync
@ComponentScan({ "org.baeldung.web" })
public class WebConfig extends WebMvcConfigurerAdapter {
@Autowired
private Environment env;
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
public ViewResolver viewResolver() {
final InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Override
public void addViewControllers(final ViewControllerRegistry registry) {
super.addViewControllers(registry);
registry.addViewController("/home.html");
}
@Bean
public OAuth2RestTemplate schedulerRedditTemplate(OAuth2ProtectedResourceDetails reddit) {
final List<ClientHttpRequestInterceptor> list = new ArrayList<ClientHttpRequestInterceptor>();
list.add(new UserAgentInterceptor());
final OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(reddit);
restTemplate.setInterceptors(list);
return restTemplate;
}
@Bean
public RedditClassifier redditClassifier() throws IOException {
final RedditClassifier redditClassifier = new RedditClassifier();
if (MyFeatures.PREDICTION_FEATURE.isActive()) {
final Resource file = new ClassPathResource("data.csv");
redditClassifier.trainClassifier(file.getFile().getAbsolutePath());
}
return redditClassifier;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
@Configuration
@EnableOAuth2Client
@PropertySource("classpath:reddit.properties")
protected static class ResourceConfiguration {
@Value("${accessTokenUri}")
private String accessTokenUri;
@Value("${userAuthorizationUri}")
private String userAuthorizationUri;
@Value("${clientID}")
private String clientID;
@Value("${clientSecret}")
private String clientSecret;
@Autowired
private PostRepository repo;
@Bean
public OAuth2ProtectedResourceDetails reddit() {
final AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
details.setId("reddit");
details.setClientId(clientID);
details.setClientSecret(clientSecret);
details.setAccessTokenUri(accessTokenUri);
details.setUserAuthorizationUri(userAuthorizationUri);
details.setTokenName("oauth_token");
details.setScope(Arrays.asList("identity", "read", "submit", "edit"));
details.setGrantType("authorization_code");
details.setPreEstablishedRedirectUri("http://localhost:8080/spring-security-oauth/login");
details.setUseCurrentUri(false);
return details;
}
@Bean
public OAuth2RestTemplate redditRestTemplate(OAuth2ClientContext clientContext) {
final OAuth2RestTemplate template = new OAuth2RestTemplate(reddit(), clientContext);
final List<ClientHttpRequestInterceptor> list = new ArrayList<ClientHttpRequestInterceptor>();
list.add(new UserAgentInterceptor());
template.setInterceptors(list);
final AccessTokenProviderChain accessTokenProvider = new AccessTokenProviderChain(Arrays.<AccessTokenProvider> asList(new MyAuthorizationCodeAccessTokenProvider(), new ImplicitAccessTokenProvider(), new ResourceOwnerPasswordAccessTokenProvider(),
new ClientCredentialsAccessTokenProvider()));
template.setAccessTokenProvider(accessTokenProvider);
return template;
}
@PostConstruct
public void startupCheck() {
if (StringUtils.isBlank(accessTokenUri) || StringUtils.isBlank(userAuthorizationUri) || StringUtils.isBlank(clientID) || StringUtils.isBlank(clientSecret)) {
throw new RuntimeException("Incomplete reddit properties");
}
repo.findAll();
}
}
}

View File

@ -1,17 +0,0 @@
package org.baeldung.persistence.dao;
import java.util.Date;
import java.util.List;
import org.baeldung.persistence.model.Post;
import org.baeldung.persistence.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PostRepository extends JpaRepository<Post, Long> {
List<Post> findBySubmissionDateBeforeAndIsSent(Date date, boolean isSent);
List<Post> findByUser(User user);
List<Post> findByRedditIDNotNullAndNoOfAttemptsGreaterThan(int attempts);
}

View File

@ -1,11 +0,0 @@
package org.baeldung.persistence.dao;
import org.baeldung.persistence.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
User findByAccessToken(String token);
}

View File

@ -1,163 +0,0 @@
package org.baeldung.persistence.model;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String subreddit;
@Column(nullable = false)
private String url;
private boolean sendReplies;
@Column(nullable = false)
private Date submissionDate;
private boolean isSent;
private String submissionResponse;
private String redditID;
private int noOfAttempts;
private int timeInterval;
private int minScoreRequired;
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private User user;
public Post() {
super();
}
public Long getId() {
return id;
}
public void setId(final Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getSubreddit() {
return subreddit;
}
public void setSubreddit(String subreddit) {
this.subreddit = subreddit;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public boolean isSendReplies() {
return sendReplies;
}
public void setSendReplies(boolean sendReplies) {
this.sendReplies = sendReplies;
}
public Date getSubmissionDate() {
return submissionDate;
}
public void setSubmissionDate(Date submissionDate) {
this.submissionDate = submissionDate;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public boolean isSent() {
return isSent;
}
public void setSent(boolean isSent) {
this.isSent = isSent;
}
public String getSubmissionResponse() {
return submissionResponse;
}
public void setSubmissionResponse(String submissionResponse) {
this.submissionResponse = submissionResponse;
}
public String getRedditID() {
return redditID;
}
public void setRedditID(String redditID) {
this.redditID = redditID;
}
public int getNoOfAttempts() {
return noOfAttempts;
}
public void setNoOfAttempts(int noOfAttempts) {
this.noOfAttempts = noOfAttempts;
}
public int getTimeInterval() {
return timeInterval;
}
public void setTimeInterval(int timeInterval) {
this.timeInterval = timeInterval;
}
public int getMinScoreRequired() {
return minScoreRequired;
}
public void setMinScoreRequired(int minScoreRequired) {
this.minScoreRequired = minScoreRequired;
}
@Override
public String toString() {
return "Post [title=" + title + ", subreddit=" + subreddit + ", url=" + url + ", submissionDate=" + submissionDate + ", user=" + user + "]";
}
}

View File

@ -1,116 +0,0 @@
package org.baeldung.persistence.model;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "APP_USER")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false)
private String username;
private String accessToken;
private String refreshToken;
private Date tokenExpiration;
private boolean needCaptcha;
public User() {
super();
}
public Long getId() {
return id;
}
public void setId(final Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(final String username) {
this.username = username;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(final String accessToken) {
this.accessToken = accessToken;
}
public String getRefreshToken() {
return refreshToken;
}
public void setRefreshToken(final String refreshToken) {
this.refreshToken = refreshToken;
}
public Date getTokenExpiration() {
return tokenExpiration;
}
public void setTokenExpiration(final Date tokenExpiration) {
this.tokenExpiration = tokenExpiration;
}
public boolean isCaptchaNeeded() {
return needCaptcha;
}
public void setNeedCaptcha(final boolean needCaptcha) {
this.needCaptcha = needCaptcha;
}
//
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = (prime * result) + ((username == null) ? 0 : username.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final User user = (User) obj;
if (!username.equals(user.username)) {
return false;
}
return true;
}
@Override
public String toString() {
return "User [username=" + username + "]";
}
}

View File

@ -1,145 +0,0 @@
package org.baeldung.persistence.service;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import org.baeldung.persistence.dao.PostRepository;
import org.baeldung.persistence.model.Post;
import org.baeldung.persistence.model.User;
import org.baeldung.reddit.util.RedditApiConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import com.fasterxml.jackson.databind.JsonNode;
@Service
public class RedditService {
@Autowired
@Qualifier("schedulerRedditTemplate")
private OAuth2RestTemplate redditRestTemplate;
@Autowired
private PostRepository postReopsitory;
private final Logger logger = LoggerFactory.getLogger(getClass());
public void submitPost(final Post post) {
try {
submitPostInternal(post);
} catch (final Exception e) {
logger.error("Error occurred while submitting post " + post.toString(), e);
}
}
public int getPostScore(String redditId) {
final JsonNode node = redditRestTemplate.getForObject("https://oauth.reddit.com/api/info?id=t3_" + redditId, JsonNode.class);
logger.info(node.toString());
final int score = node.get("data").get("children").get(0).get("data").get("score").asInt();
logger.info("post score = " + score);
return score;
}
public void deletePost(String redditId) {
final MultiValueMap<String, String> param = new LinkedMultiValueMap<String, String>();
param.add("id", "t3_" + redditId);
final JsonNode node = redditRestTemplate.postForObject("https://oauth.reddit.com/api/del.json", param, JsonNode.class);
logger.info(node.toString());
}
public void checkAndReSubmit(Post post) {
try {
checkAndReSubmitInternal(post);
} catch (final Exception e) {
logger.error("Error occurred while check post " + post.toString(), e);
}
}
// === private methods
private void submitPostInternal(final Post post) {
final User user = post.getUser();
final DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(user.getAccessToken());
token.setRefreshToken(new DefaultOAuth2RefreshToken((user.getRefreshToken())));
token.setExpiration(user.getTokenExpiration());
redditRestTemplate.getOAuth2ClientContext().setAccessToken(token);
//
final UsernamePasswordAuthenticationToken userAuthToken = new UsernamePasswordAuthenticationToken(user.getUsername(), token.getValue(), Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")));
SecurityContextHolder.getContext().setAuthentication(userAuthToken);
//
final MultiValueMap<String, String> param = new LinkedMultiValueMap<String, String>();
param.add(RedditApiConstants.TITLE, post.getTitle());
param.add(RedditApiConstants.SR, post.getSubreddit());
param.add(RedditApiConstants.URL, post.getUrl());
param.add(RedditApiConstants.API_TYPE, "json");
param.add(RedditApiConstants.KIND, "link");
param.add(RedditApiConstants.RESUBMIT, "true");
param.add(RedditApiConstants.THEN, "comments");
if (post.isSendReplies()) {
param.add(RedditApiConstants.SENDREPLIES, "true");
}
logger.info("Submit link with these parameters: " + param.entrySet());
final JsonNode node = redditRestTemplate.postForObject("https://oauth.reddit.com/api/submit", param, JsonNode.class);
parseResponse(node, post);
}
private void parseResponse(JsonNode node, Post post) {
final JsonNode errorNode = node.get("json").get("errors").get(0);
if (errorNode == null) {
post.setSent(true);
post.setSubmissionResponse("Successfully sent");
post.setRedditID(node.get("json").get("data").get("id").asText());
post.setNoOfAttempts(post.getNoOfAttempts() - 1);
postReopsitory.save(post);
logger.info("Successfully sent " + post.toString());
} else {
post.setSubmissionResponse(errorNode.toString());
postReopsitory.save(post);
logger.info("Error occurred: " + errorNode.toString() + "while submitting post " + post.toString());
}
}
private void checkAndReSubmitInternal(Post post) {
if (didIntervalPassed(post.getSubmissionDate(), post.getTimeInterval())) {
final int score = getPostScore(post.getRedditID());
if (score < post.getMinScoreRequired()) {
deletePost(post.getRedditID());
resetPost(post);
} else {
post.setNoOfAttempts(0);
postReopsitory.save(post);
}
}
}
private boolean didIntervalPassed(Date submissonDate, int postInterval) {
final long currentTime = new Date().getTime();
final long interval = currentTime - submissonDate.getTime();
final long intervalInMinutes = TimeUnit.MINUTES.convert(interval, TimeUnit.MILLISECONDS);
return intervalInMinutes > postInterval;
}
private void resetPost(Post post) {
long time = new Date().getTime();
time += TimeUnit.MILLISECONDS.convert(post.getTimeInterval(), TimeUnit.MINUTES);
post.setRedditID(null);
post.setSubmissionDate(new Date(time));
post.setSent(false);
post.setSubmissionResponse("Not sent yet");
postReopsitory.save(post);
}
}

View File

@ -1,168 +0,0 @@
package org.baeldung.reddit.classifier;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.TimeZone;
import org.apache.mahout.classifier.sgd.AdaptiveLogisticRegression;
import org.apache.mahout.classifier.sgd.CrossFoldLearner;
import org.apache.mahout.classifier.sgd.L2;
import org.apache.mahout.math.NamedVector;
import org.apache.mahout.math.RandomAccessSparseVector;
import org.apache.mahout.math.Vector;
import org.apache.mahout.vectorizer.encoders.AdaptiveWordValueEncoder;
import org.apache.mahout.vectorizer.encoders.FeatureVectorEncoder;
import org.apache.mahout.vectorizer.encoders.StaticWordValueEncoder;
import com.google.common.base.Splitter;
import com.google.common.io.Files;
public class RedditClassifier {
public static int GOOD = 0;
public static int BAD = 1;
private final int[] trainCount = { 0, 0 };
private final int[] evalCount = { 0, 0 };
private final int[] correctCount = { 0, 0 };
private final AdaptiveLogisticRegression classifier;
private final FeatureVectorEncoder titleEncoder;
private final FeatureVectorEncoder domainEncoder;
private final int noOfFeatures;
private final int minScore;
private CrossFoldLearner learner;
private double accuracy;
public RedditClassifier() {
this(150, 1000, 7);
}
public RedditClassifier(final int poolSize, final int noOfFeatures, int minScore) {
this.minScore = minScore;
this.noOfFeatures = noOfFeatures;
classifier = new AdaptiveLogisticRegression(2, noOfFeatures, new L2());
classifier.setPoolSize(poolSize);
titleEncoder = new AdaptiveWordValueEncoder("title");
titleEncoder.setProbes(1);
domainEncoder = new StaticWordValueEncoder("domain");
domainEncoder.setProbes(1);
}
// API
public void trainClassifier(final String fileName) throws IOException {
final List<NamedVector> vectors = extractVectors(readDataFile(fileName));
final int size = vectors.size();
final int noOfTraining = (int) (size * 0.8);
final List<NamedVector> trainingData = vectors.subList(0, noOfTraining);
final List<NamedVector> testData = vectors.subList(noOfTraining, size);
int category;
for (final NamedVector vector : trainingData) {
category = (vector.getName() == "GOOD") ? GOOD : BAD;
classifier.train(category, vector);
trainCount[category]++;
}
System.out.println("Training count ========= Good = " + trainCount[0] + " ___ Bad = " + trainCount[1]);
System.out.println("----------------------------------------------------------------- \n");
evaluateClassifier(testData);
}
public Vector convertPost(final String title, final String domain, final int hour) {
final Vector vector = new RandomAccessSparseVector(noOfFeatures);
final List<String> words = Splitter.onPattern("\\W").omitEmptyStrings().splitToList(title);
vector.set(0, hour);
vector.set(1, words.size());
domainEncoder.addToVector(domain, vector);
for (final String word : words) {
titleEncoder.addToVector(word, vector);
}
return vector;
}
public int classify(final Vector features) {
if (learner == null) {
learner = classifier.getBest().getPayload().getLearner();
}
return learner.classifyFull(features).maxValueIndex();
}
public double getAccuracy() {
return accuracy;
}
// ==== Private methods
private void evaluateClassifier(final List<NamedVector> vectors) throws IOException {
int category, result;
int correct = 0;
int wrong = 0;
for (final NamedVector vector : vectors) {
category = (vector.getName() == "GOOD") ? GOOD : BAD;
result = classify(vector);
evalCount[category]++;
if (category == result) {
correct++;
correctCount[result]++;
} else {
wrong++;
}
}
System.out.println("Eval count =================== Good = " + evalCount[0] + " ----- Bad = " + evalCount[1] + "\n");
System.out.println("Overall Evaluation ============= Correct prediction = " + correct + " ----- Wrong prediction = " + wrong);
System.out.println("Correctly Evaluated =========== Correct Good = " + correctCount[0] + " ----- Correct Bad = " + correctCount[1]);
System.out.println("Correctly Evaluated (%) ======== Good accuracy = " + (correctCount[0] / (evalCount[0] + 0.0)) + " ----- Bad accuracy = " + (correctCount[1] / (evalCount[1] + 0.0)));
this.accuracy = correct / (wrong + correct + 0.0);
}
private List<String> readDataFile(final String fileName) throws IOException {
List<String> lines = Files.readLines(new File(fileName), Charset.forName("utf-8"));
if ((lines == null) || (lines.size() == 0)) {
new RedditDataCollector().collectData();
lines = Files.readLines(new File(fileName), Charset.forName("utf-8"));
}
lines.remove(0);
return lines;
}
private List<NamedVector> extractVectors(final List<String> lines) {
final List<NamedVector> vectors = new ArrayList<NamedVector>(lines.size());
for (final String line : lines) {
vectors.add(extractVector(line));
}
return vectors;
}
private NamedVector extractVector(final String line) {
final String[] items = line.split(",");
final String numberOfVotes = items[0];
final String time = items[1];
final String numberOfWordInTitle = items[2];
final String title = items[3];
final String theRootDomain = items[4];
final RandomAccessSparseVector internalVector = new RandomAccessSparseVector(noOfFeatures);
final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
cal.setTimeInMillis(Long.parseLong(time) * 1000);
internalVector.set(0, cal.get(Calendar.HOUR_OF_DAY)); // hour of day
internalVector.set(1, Integer.parseInt(numberOfWordInTitle)); // number of words in the title
domainEncoder.addToVector(theRootDomain, internalVector);
final List<String> words = Splitter.on(' ').splitToList(title);
words.stream().filter(word -> word.length() > 2).forEach(word -> titleEncoder.addToVector(word, internalVector));
final String category = extractCategory(Integer.parseInt(numberOfVotes));
return new NamedVector(internalVector, category);
}
private String extractCategory(final int score) {
return (score < minScore) ? "BAD" : "GOOD";
}
}

View File

@ -1,88 +0,0 @@
package org.baeldung.reddit.classifier;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.baeldung.reddit.util.UserAgentInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
public class RedditDataCollector {
public static final String DATA_FILE = "src/main/resources/data.csv";
public static final int DATA_SIZE = 20000;
public static final int LIMIT = 100;
public static final Long YEAR = 31536000L;
private final Logger logger = LoggerFactory.getLogger(getClass());
private Long timestamp;
private final RestTemplate restTemplate;
private final String subreddit;
public RedditDataCollector() {
this("java");
}
public RedditDataCollector(String subreddit) {
restTemplate = new RestTemplate();
final List<ClientHttpRequestInterceptor> list = new ArrayList<ClientHttpRequestInterceptor>();
list.add(new UserAgentInterceptor());
restTemplate.setInterceptors(list);
this.subreddit = subreddit;
}
public void collectData() throws IOException {
final int noOfRounds = DATA_SIZE / LIMIT;
timestamp = System.currentTimeMillis() / 1000;
final FileWriter writer = new FileWriter(DATA_FILE);
writer.write("Score, Timestamp in utc, Number of wrods in title, Title, Domain \n");
for (int i = 0; i < noOfRounds; i++) {
getPosts(writer);
System.out.println(i);
}
writer.close();
}
// ==== Private
private void getPosts(FileWriter writer) {
final String fullUrl = "http://www.reddit.com/r/" + subreddit + "/search.json?sort=new&q=timestamp:" + (timestamp - YEAR) + ".." + timestamp + "&restrict_sr=on&syntax=cloudsearch&limit=" + LIMIT;
try {
final JsonNode node = restTemplate.getForObject(fullUrl, JsonNode.class);
parseNode(node, writer);
Thread.sleep(3000);
} catch (final Exception e) {
logger.error("server error", e);
}
}
private void parseNode(JsonNode node, FileWriter writer) throws IOException {
String line;
List<String> words;
int score;
for (final JsonNode child : node.get("data").get("children")) {
score = child.get("data").get("score").asInt();
words = Splitter.onPattern("\\W").omitEmptyStrings().splitToList(child.get("data").get("title").asText());
timestamp = child.get("data").get("created_utc").asLong();
line = score + ",";
line += timestamp + ",";
line += words.size() + "," + Joiner.on(' ').join(words) + ",";
line += child.get("data").get("domain").asText() + "\n";
writer.write(line);
}
}
public static void main(String[] args) throws IOException {
final RedditDataCollector collector = new RedditDataCollector();
collector.collectData();
}
}

View File

@ -1,17 +0,0 @@
package org.baeldung.reddit.util;
public enum MyFeatures {
PREDICTION_FEATURE(false);
private boolean active;
private MyFeatures(boolean active) {
this.active = active;
}
public boolean isActive() {
return this.active;
}
}

View File

@ -1,19 +0,0 @@
package org.baeldung.reddit.util;
/**
* Specified by Reddit API at http://www.reddit.com/dev/api#POST_api_submit
*/
public final class RedditApiConstants {
public static final String API_TYPE = "api_type";
public static final String URL = "url";
public static final String SR = "sr";
public static final String TITLE = "title";
public static final String THEN = "then";
public static final String SENDREPLIES = "sendreplies";
public static final String RESUBMIT = "resubmit";
public static final String KIND = "kind";
private RedditApiConstants() {
throw new AssertionError();
}
}

View File

@ -1,20 +0,0 @@
package org.baeldung.reddit.util;
import java.io.IOException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
public class UserAgentInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
final HttpHeaders headers = request.getHeaders();
headers.add("User-Agent", "Schedule with Reddit");
return execution.execute(request, body);
}
}

View File

@ -1,275 +0,0 @@
package org.baeldung.web;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.baeldung.persistence.dao.PostRepository;
import org.baeldung.persistence.dao.UserRepository;
import org.baeldung.persistence.model.Post;
import org.baeldung.persistence.model.User;
import org.baeldung.reddit.classifier.RedditClassifier;
import org.baeldung.reddit.util.RedditApiConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import com.fasterxml.jackson.databind.JsonNode;
@Controller
public class RedditController {
private final Logger logger = LoggerFactory.getLogger(getClass());
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
private final SimpleDateFormat dfHour = new SimpleDateFormat("HH");
@Autowired
@Qualifier("redditRestTemplate")
private OAuth2RestTemplate redditRestTemplate;
@Autowired
private UserRepository userReopsitory;
@Autowired
private PostRepository postReopsitory;
@Autowired
private RedditClassifier redditClassifier;
@RequestMapping("/login")
public final String redditLogin() {
final JsonNode node = redditRestTemplate.getForObject("https://oauth.reddit.com/api/v1/me", JsonNode.class);
loadAuthentication(node.get("name").asText(), redditRestTemplate.getAccessToken());
return "redirect:home.html";
}
@RequestMapping(value = "/submit", method = RequestMethod.POST)
public final String submit(final Model model, @RequestParam final Map<String, String> formParams) {
final MultiValueMap<String, String> param1 = constructParams(formParams);
logger.info("Submitting Link with these parameters: " + param1);
final JsonNode node = redditRestTemplate.postForObject("https://oauth.reddit.com/api/submit", param1, JsonNode.class);
logger.info("Submitted Link - Full Response from Reddit: " + node.toString());
final String responseMsg = parseResponse(node);
model.addAttribute("msg", responseMsg);
return "submissionResponse";
}
@RequestMapping("/post")
public final String showSubmissionForm(final Model model) {
final boolean isCaptchaNeeded = getCurrentUser().isCaptchaNeeded();
if (isCaptchaNeeded) {
final String iden = getNewCaptcha();
model.addAttribute("iden", iden);
}
return "submissionForm";
}
@RequestMapping("/postSchedule")
public final String showSchedulePostForm(final Model model) {
final boolean isCaptchaNeeded = getCurrentUser().isCaptchaNeeded();
if (isCaptchaNeeded) {
model.addAttribute("msg", "Sorry, You do not have enought karma");
return "submissionResponse";
}
return "schedulePostForm";
}
@RequestMapping(value = "/schedule", method = RequestMethod.POST)
public final String schedule(final Model model, @RequestParam final Map<String, String> formParams) throws ParseException {
logger.info("User scheduling Post with these parameters: " + formParams.entrySet());
final User user = getCurrentUser();
final Post post = new Post();
post.setUser(user);
post.setSent(false);
post.setTitle(formParams.get("title"));
post.setSubreddit(formParams.get("sr"));
post.setUrl(formParams.get("url"));
post.setNoOfAttempts(Integer.parseInt(formParams.get("attempt")));
post.setTimeInterval(Integer.parseInt(formParams.get("interval")));
post.setMinScoreRequired(Integer.parseInt(formParams.get("score")));
if (formParams.containsKey("sendreplies")) {
post.setSendReplies(true);
}
post.setSubmissionDate(dateFormat.parse(formParams.get("date")));
post.setSubmissionResponse("Not sent yet");
if (post.getSubmissionDate().before(new Date())) {
model.addAttribute("msg", "Invalid date");
return "submissionResponse";
}
postReopsitory.save(post);
final List<Post> posts = postReopsitory.findByUser(user);
model.addAttribute("posts", posts);
return "postListView";
}
@RequestMapping("/posts")
public final String getScheduledPosts(final Model model) {
final User user = getCurrentUser();
final List<Post> posts = postReopsitory.findByUser(user);
model.addAttribute("posts", posts);
return "postListView";
}
@RequestMapping(value = "/predicatePostResponse", method = RequestMethod.POST)
@ResponseBody
public final String predicatePostResponse(@RequestParam(value = "title") final String title, @RequestParam(value = "domain") final String domain) {
final int hour = Integer.parseInt(dfHour.format(new Date()));
final int result = redditClassifier.classify(redditClassifier.convertPost(title, domain, hour));
return (result == RedditClassifier.GOOD) ? "{Good Response}" : "{Bad response}";
}
@RequestMapping(value = "/checkIfAlreadySubmitted", method = RequestMethod.POST)
@ResponseBody
public String checkIfAlreadySubmitted(@RequestParam("url") final String url, @RequestParam("sr") final String sr) {
logger.info("check if already submitted");
final JsonNode node = redditRestTemplate.getForObject("https://oauth.reddit.com/r/" + sr + "/search?q=url:" + url + "&restrict_sr=on", JsonNode.class);
logger.info(node.toString());
return node.get("data").get("children").toString();
}
@RequestMapping(value = "/subredditAutoComplete")
@ResponseBody
public String subredditAutoComplete(@RequestParam("term") final String term) {
final MultiValueMap<String, String> param = new LinkedMultiValueMap<String, String>();
param.add("query", term);
final JsonNode node = redditRestTemplate.postForObject("https://oauth.reddit.com//api/search_reddit_names", param, JsonNode.class);
return node.get("names").toString();
}
// === post actions
@RequestMapping(value = "/deletePost/{id}", method = RequestMethod.DELETE)
@ResponseStatus(HttpStatus.OK)
public void deletePost(@PathVariable("id") final Long id) {
postReopsitory.delete(id);
}
@RequestMapping(value = "/editPost/{id}", method = RequestMethod.GET)
public String showEditPostForm(final Model model, @PathVariable Long id) {
final Post post = postReopsitory.findOne(id);
model.addAttribute("post", post);
model.addAttribute("dateValue", dateFormat.format(post.getSubmissionDate()));
return "editPostForm";
}
@RequestMapping(value = "/updatePost/{id}", method = RequestMethod.POST)
public String updatePost(Model model, @PathVariable("id") final Long id, @RequestParam final Map<String, String> formParams) throws ParseException {
final Post post = postReopsitory.findOne(id);
post.setTitle(formParams.get("title"));
post.setSubreddit(formParams.get("sr"));
post.setUrl(formParams.get("url"));
post.setNoOfAttempts(Integer.parseInt(formParams.get("attempt")));
post.setTimeInterval(Integer.parseInt(formParams.get("interval")));
post.setMinScoreRequired(Integer.parseInt(formParams.get("score")));
if (formParams.containsKey("sendreplies")) {
post.setSendReplies(true);
} else {
post.setSendReplies(false);
}
post.setSubmissionDate(dateFormat.parse(formParams.get("date")));
if (post.getSubmissionDate().before(new Date())) {
model.addAttribute("msg", "Invalid date");
return "submissionResponse";
}
postReopsitory.save(post);
return "redirect:/posts";
}
// === private
private User getCurrentUser() {
return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
private final MultiValueMap<String, String> constructParams(final Map<String, String> formParams) {
final MultiValueMap<String, String> param = new LinkedMultiValueMap<String, String>();
param.add(RedditApiConstants.API_TYPE, "json");
param.add(RedditApiConstants.KIND, "link");
param.add(RedditApiConstants.RESUBMIT, "true");
param.add(RedditApiConstants.THEN, "comments");
for (final Map.Entry<String, String> entry : formParams.entrySet()) {
param.add(entry.getKey(), entry.getValue());
}
return param;
}
private final String needsCaptcha() {
final String result = redditRestTemplate.getForObject("https://oauth.reddit.com/api/needs_captcha.json", String.class);
return result;
}
private final String getNewCaptcha() {
final Map<String, String> param = new HashMap<String, String>();
param.put("api_type", "json");
final String result = redditRestTemplate.postForObject("https://oauth.reddit.com/api/new_captcha", param, String.class, param);
final String[] split = result.split("\"");
return split[split.length - 2];
}
private final String parseResponse(final JsonNode node) {
String result = "";
final JsonNode errorNode = node.get("json").get("errors").get(0);
if (errorNode != null) {
for (final JsonNode child : errorNode) {
result = result + child.toString().replaceAll("\"|null", "") + "<br>";
}
return result;
} else {
if ((node.get("json").get("data") != null) && (node.get("json").get("data").get("url") != null)) {
return "Post submitted successfully " + node.get("json").get("data").get("url").asText();
} else {
return "Error Occurred";
}
}
}
private void loadAuthentication(final String name, final OAuth2AccessToken token) {
User user = userReopsitory.findByUsername(name);
if (user == null) {
user = new User();
user.setUsername(name);
}
if (needsCaptcha().equalsIgnoreCase("true")) {
user.setNeedCaptcha(true);
} else {
user.setNeedCaptcha(false);
}
user.setAccessToken(token.getValue());
user.setRefreshToken(token.getRefreshToken().getValue());
user.setTokenExpiration(token.getExpiration());
userReopsitory.save(user);
final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user, token.getValue(), Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")));
SecurityContextHolder.getContext().setAuthentication(auth);
}
}

View File

@ -1,69 +0,0 @@
package org.baeldung.web;
import java.io.Serializable;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
import org.springframework.security.oauth2.client.resource.UserApprovalRequiredException;
import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler implements Serializable {
private static final long serialVersionUID = -3861125729653781371L;
public RestExceptionHandler() {
super();
}
// API
// 4xx
@ExceptionHandler({ OAuth2AccessDeniedException.class })
public ModelAndView handleOAuth2AccessDeniedException(final OAuth2AccessDeniedException ex, final WebRequest request) {
logger.error("403 Status Code", ex);
final String response = "Error Occurred - Forbidden: " + ex.getMessage();
final ModelAndView model = new ModelAndView("submissionResponse");
model.addObject("msg", response);
return model;
// return handleExceptionInternal(ex, response, new HttpHeaders(), HttpStatus.FORBIDDEN, request);
}
@ExceptionHandler({ HttpClientErrorException.class })
public ModelAndView handleHttpClientErrorException(final HttpClientErrorException ex, final WebRequest request) {
logger.error("400 Status Code", ex);
final String response = "Error Occurred - To Many Requests: " + ex.getMessage();
final ModelAndView model = new ModelAndView("submissionResponse");
model.addObject("msg", response);
return model;
// return handleExceptionInternal(ex, response, new HttpHeaders(), HttpStatus.TOO_MANY_REQUESTS, request);
}
// HttpClientErrorException
// 500
@ExceptionHandler({ UserApprovalRequiredException.class, UserRedirectRequiredException.class })
public ResponseEntity<Object> handleRedirect(final RuntimeException ex, final WebRequest request) {
logger.info(ex.getLocalizedMessage());
throw ex;
}
@ExceptionHandler({ Exception.class })
public ModelAndView handleInternal(final RuntimeException ex, final WebRequest request, final HttpServletResponse response) {
logger.info(response.getHeader("x-ratelimit-remaining"));
logger.error("500 Status Code", ex);
final String message = "Error Occurred: " + ex.getLocalizedMessage();
final ModelAndView model = new ModelAndView("submissionResponse");
model.addObject("msg", message);
return model;
}
}

View File

@ -1,44 +0,0 @@
package org.baeldung.web.schedule;
import java.util.Date;
import java.util.List;
import org.baeldung.persistence.dao.PostRepository;
import org.baeldung.persistence.model.Post;
import org.baeldung.persistence.service.RedditService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class RedditScheduler {
@Autowired
private RedditService service;
@Autowired
private PostRepository postReopsitory;
private final Logger logger = LoggerFactory.getLogger(getClass());
@Scheduled(fixedRate = 1 * 60 * 1000)
public void schedulePosts() {
final List<Post> posts = postReopsitory.findBySubmissionDateBeforeAndIsSent(new Date(), false);
logger.info(posts.size() + " Posts in the queue.");
for (final Post post : posts) {
service.submitPost(post);
}
}
@Scheduled(fixedRate = 3 * 60 * 1000)
public void checkAndReSubmitPosts() {
final List<Post> submitted = postReopsitory.findByRedditIDNotNullAndNoOfAttemptsGreaterThan(0);
logger.info(submitted.size() + " Posts to check their score");
for (final Post post : submitted) {
service.checkAndReSubmit(post);
}
}
}

View File

@ -1 +0,0 @@
persistence.properties

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +0,0 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>web - %date [%thread] %-5level %logger{36} - %message%n
</pattern>
</encoder>
</appender>
<logger name="org.springframework" level="WARN" />
<logger name="org.springframework.transaction" level="WARN" />
<!-- in order to debug some marshalling issues, this needs to be TRACE -->
<logger name="org.springframework.web.servlet.mvc" level="WARN" />
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -1,10 +0,0 @@
################### DataSource Configuration ##########################
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/oauth_reddit?createDatabaseIfNotExist=true
jdbc.user=tutorialuser
jdbc.pass=tutorialmy5ql
init-db=false
################### Hibernate Configuration ##########################
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=false
hibernate.hbm2ddl.auto=update

View File

@ -1,10 +0,0 @@
################### DataSource Configuration ##########################
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/oauth_reddit?createDatabaseIfNotExist=true
jdbc.user=tutorialuser
jdbc.pass=tutorialmy5ql
init-db=false
################### Hibernate Configuration ##########################
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=false
hibernate.hbm2ddl.auto=create-drop

View File

@ -1,9 +0,0 @@
################### DataSource Configuration ##########################
jdbc.driverClassName=org.postgresql.Driver
jdbc.url=jdbc:postgresql://ec2-184-73-253-4.compute-1.amazonaws.com:5432/d3th4rkdb2g3p6?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory
jdbc.user=fhjspqyblvawvp
jdbc.pass=gRKGJbdHXslq0XgdI03j2Y4YoE
################### Hibernate Configuration ##########################
hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
hibernate.show_sql=false
hibernate.hbm2ddl.auto=create-drop

View File

@ -1,10 +0,0 @@
################### DataSource Configuration ##########################
jdbc.driverClassName=org.h2.Driver
jdbc.url=jdbc:h2:mem:oauth_reddit;DB_CLOSE_DELAY=-1
jdbc.user=sa
jdbc.pass=
init-db=false
################### Hibernate Configuration ##########################
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.show_sql=false
hibernate.hbm2ddl.auto=update

View File

@ -1,4 +0,0 @@
clientID=5iAHD5-BBmEL8Q
clientSecret=grkII6-THVcFsMm1wVTiQDRONmw
accessTokenUri=https://www.reddit.com/api/v1/access_token
userAuthorizationUri=https://www.reddit.com/api/v1/authorize

View File

@ -1,103 +0,0 @@
<html>
<head>
<title>Schedule to Reddit</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"/>
<link rel="stylesheet" th:href="@{/resources/datetime-picker.css}" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script th:src="@{/resources/datetime-picker.js}"></script>
<script th:src="@{/resources/validator.js}"></script>
<style type="text/css">
.btn.disabled{
background-color: #ddd;
border-color: #ddd;
}
.btn.disabled:hover{
background-color: #ddd;
border-color: #ddd;
}
</style>
</head>
<body>
<div th:include="header"/>
<div class="container">
<h1>Edit Scheduled Post</h1>
<form th:action="@{/updatePost/{id}(id=${post.getId()})}" method="post" role="form" data-toggle="validator">
<div class="row">
<input type="hidden" name="id" value="${post.getId()}"/>
<div class="form-group">
<label class="col-sm-3">Title</label>
<span class="col-sm-9"><input name="title" placeholder="title" class="form-control" th:value="${post.getTitle()}" required="required" data-minlength="3"/></span>
</div>
<br/><br/>
<div class="form-group">
<label class="col-sm-3">Url</label>
<span class="col-sm-9"><input name="url" type="url" placeholder="url" class="form-control" th:value="${post.getUrl()}" required="required" data-minlength="3"/></span>
</div>
<br/><br/>
<div class="form-group">
<label class="col-sm-3">Subreddit</label>
<span class="col-sm-9"><input name="sr" placeholder="Subreddit" class="form-control" th:value="${post.getSubreddit()}" required="required" data-minlength="3"/></span>
</div>
<br/><br/>
<div>
<label class="col-sm-3">Send replies to my inbox</label>
<span class="col-sm-9">
<input th:if="${post.isSendReplies()=='true'}" type="checkbox" name="sendreplies" value="true" checked="checked"/>
<input th:if="${post.isSendReplies()=='false'}" type="checkbox" name="sendreplies" value="true" checked="checked"/>
</span>
</div>
<br/><br/>
<br/>
<hr/>
<br/>
<div class="form-group">
<label class="col-sm-3">Resubmit If:</label>
<span class="col-sm-2">Votes didn't exceed </span>
<span class="col-sm-1">
<input type="number" class="form-control input-sm" th:value="${post.getMinScoreRequired()}" name="score" required="required"/>
</span>
<span class="col-sm-3">within &nbsp;&nbsp;
<select name="interval">
<option value="0" th:selected="${post.getTimeInterval() == 0}">None</option>
<option value="45" th:selected="${post.getTimeInterval() == 45}">45 minutes</option>
<option value="60" th:selected="${post.getTimeInterval() == 60}">1 hour</option>
<option value="120" th:selected="${post.getTimeInterval() == 120}">2 hours</option>
</select>
</span>
<span class="col-sm-3">try resubmitting &nbsp;&nbsp;
<select name="attempt">
<option value="0" th:selected="${post.getNoOfAttempts() == 0}">No</option>
<option value="1" th:selected="${post.getNoOfAttempts() == 1}">1</option>
<option value="2" th:selected="${post.getNoOfAttempts() == 2}">2</option>
<option value="3" th:selected="${post.getNoOfAttempts() == 3}">3</option>
<option value="4" th:selected="${post.getNoOfAttempts() == 4}">4</option>
<option value="5" th:selected="${post.getNoOfAttempts() == 5}">5</option>
</select>
&nbsp;&nbsp; times.
</span>
</div>
<br/><br/>
<label class="col-sm-3">Submission Date (<span th:text="${#dates.format(#calendars.createToday(), 'z')}">UTC</span>)</label>
<span class="col-sm-9"><input type="text" name="date" class="form-control" th:value="${dateValue}" readonly="readonly"/></span>
<script type="text/javascript">
$(function(){
$('*[name=date]').appendDtpicker({"inline": true});
});
</script>
<br/><br/>
<button type="submit" class="btn btn-primary">Save Changes</button>
</div>
</form>
</div>
</body>
</html>

View File

@ -1,23 +0,0 @@
<div>
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" th:href="@{/home.html}">Schedule to Reddit</a>
</div>
<p class="navbar-text navbar-right">Logged in as
<b><span sec:authentication="principal.username">Bob</span></b>&nbsp;&nbsp;&nbsp;
<a th:href="@{/logout}">Logout</a>&nbsp;&nbsp;&nbsp;
</p>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li><a th:href="@{/posts}">My Scheduled Posts</a></li>
<li><a th:href="@{/post}">Post to Reddit</a></li>
<li><a th:href="@{/postSchedule}">Schedule Post to Reddit</a></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
</div>

View File

@ -1,19 +0,0 @@
<html>
<head>
<title>Schedule to Reddit</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"/>
</head>
<body>
<div th:include="header"/>
<div class="container">
<h1>Welcome, <small><span sec:authentication="principal.username">Bob</span></small></h1>
<br/>
<a href="posts" class="btn btn-primary">My Scheduled Posts</a>
<a href="post" class="btn btn-primary">Post to Reddit</a>
<a href="postSchedule" class="btn btn-primary">Schedule Post to Reddit</a>
</div>
</body>
</html>

View File

@ -1,57 +0,0 @@
<html>
<head>
<title>Schedule to Reddit</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"/>
</head>
<body>
<div th:include="header"/>
<div class="container">
<h1>My Scheduled Posts</h1>
<table class="table table-bordered">
<thead>
<tr>
<th>Post title</th>
<th>Submission Date</th>
<th>Status</th>
<th>Resubmit Attempts left</th>
<th>Actions</th>
</tr>
</thead>
<tr th:each="post : ${posts}">
<td th:text="${post.getTitle()}"></td>
<td th:text="${#calendars.format(post.getSubmissionDate(),'dd MMMM yyyy HH:mm z')}"></td>
<td th:text="${post.getSubmissionResponse()}"></td>
<td th:if="${post.getNoOfAttempts() > 0}" th:text="${post.getNoOfAttempts()}"></td>
<td th:unless="${post.getNoOfAttempts() > 0}">-</td>
<td>
<a th:href="@{/editPost/{id}(id=${post.getId()})}" class="btn btn-warning" >Edit</a>
<a href="#" class="btn btn-danger" th:onclick="'javascript:confirmDelete(\'' +${post.getId()}+ '\') '">Delete</a>
</td>
</tr>
</table>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script>
/*<![CDATA[*/
function confirmDelete(id) {
if (confirm("Do you really want to delete this post?") == true) {
deletePost(id);
}
}
function deletePost(id){
$.ajax({
url: 'deletePost/'+id,
type: 'DELETE',
success: function(result) {
window.location.href="posts"
}
});
}
/*]]>*/
</script>
</body>
</html>

View File

@ -1,145 +0,0 @@
<html>
<head>
<title>Schedule to Reddit</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"/>
<link rel="stylesheet" th:href="@{/resources/datetime-picker.css}"/>
<link rel="stylesheet" th:href="@{/resources/autocomplete.css}"/>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<script th:src="@{/resources/datetime-picker.js}"></script>
<script th:src="@{/resources/validator.js}"></script>
<style type="text/css">
.btn.disabled{
background-color: #ddd;
border-color: #ddd;
}
.btn.disabled:hover{
background-color: #ddd;
border-color: #ddd;
}
</style>
</head>
<body>
<div th:include="header"/>
<div class="container">
<h1>Schedule Post to Reddit</h1>
<form action="schedule" method="post" role="form" data-toggle="validator">
<div class="row">
<div class="form-group">
<label class="col-sm-3">Title</label>
<span class="col-sm-9"><input name="title" placeholder="title" class="form-control" required="required" data-minlength="3"/></span>
</div>
<br/><br/>
<div class="form-group">
<label class="col-sm-3">Url</label>
<span class="col-sm-9"><input name="url" type="url" placeholder="url" class="form-control" required="required" data-minlength="3"/></span>
</div>
<br/><br/>
<div class="form-group">
<label class="col-sm-3">Subreddit</label>
<span class="col-sm-9"><input id="sr" name="sr" placeholder="Subreddit (e.g. kitten)" class="form-control" required="required" data-minlength="3"/></span>
</div>
<br/><br/>
<div>
<label class="col-sm-3">Send replies to my inbox</label> <span class="col-sm-9"><input type="checkbox" name="sendreplies" value="true"/></span>
</div>
<br/><br/>
<div>
<span class="col-sm-2"><a href="#" class="btn btn-default" onclick="checkIfAlreadySubmitted()">Check if already submitted</a></span>
<span class="col-sm-1"></span>
<span class="col-sm-9"><span id="checkResult" class="alert alert-info" style="display:none"></span></span>
</div>
<br/><br/>
<hr/>
<div class="form-group">
<label class="col-sm-3">Resubmit If:</label>
<span class="col-sm-2">Votes didn't exceed </span>
<span class="col-sm-1">
<input type="number" class="form-control input-sm" value="0" name="score" required="required"/>
</span>
<span class="col-sm-3">within &nbsp;&nbsp;
<select name="interval">
<option value="0" selected="selected">None</option>
<option value="45">45 minutes</option>
<option value="60">1 hour</option>
<option value="120">2 hours</option>
</select>
</span>
<span class="col-sm-3">try resubmitting &nbsp;&nbsp;
<select name="attempt">
<option value="0" selected="selected">No</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
&nbsp;&nbsp; times.
</span>
</div>
<br/><br/>
<label class="col-sm-3">Submission Date (<span th:text="${#dates.format(#calendars.createToday(), 'z')}">UTC</span>)</label>
<span class="col-sm-9"><input type="text" name="date" class="form-control" readonly="readonly"/></span>
<script type="text/javascript">
/*<![CDATA[*/
$(function(){
$('*[name=date]').appendDtpicker({"inline": true});
});
/*]]>*/
</script>
<br/><br/>
<button type="submit" class="btn btn-primary">Schedule</button>
</div>
</form>
</div>
<script>
$(function() {
$( "#sr" ).autocomplete({
source: "subredditAutoComplete"
});
$("input[name='url'],input[name='sr']").focus(function (){
$("#checkResult").hide();
});
});
</script>
<script>
/*<![CDATA[*/
function checkIfAlreadySubmitted(){
var url = $("input[name='url']").val();
var sr = $("input[name='sr']").val();
console.log(url);
if(url.length >3 && sr.length > 3){
$.post("checkIfAlreadySubmitted",{url: url, sr: sr}, function(data){
var result = JSON.parse(data);
if(result.length == 0){
$("#checkResult").show().html("Not submitted before");
}else{
$("#checkResult").show().html('Already submitted <b><a target="_blank" href="http://www.reddit.com'+result[0].data.permalink+'">here</a></b>');
}
});
}
else{
$("#checkResult").show().html("Too short url and/or subreddit");
}
}
/*]]>*/
</script>
</body>
</html>

View File

@ -1,136 +0,0 @@
<html>
<head>
<title>Schedule to Reddit</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"/>
<link rel="stylesheet" th:href="@{/resources/autocomplete.css}"/>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script>
<script th:src="@{/resources/validator.js}"></script>
<style type="text/css">
.btn.disabled{
background-color: #ddd;
border-color: #ddd;
}
.btn.disabled:hover{
background-color: #ddd;
border-color: #ddd;
}
</style>
</head>
<body>
<div th:include="header"/>
<div class="container">
<h1>Post to Reddit</h1>
<form action="submit" method="post" role="form" data-toggle="validator">
<div class="row">
<div class="form-group">
<label class="col-sm-3">Title</label>
<span class="col-sm-9"><input name="title" placeholder="title" class="form-control" data-minlength="3" required="required"/></span>
</div>
<br/><br/>
<div class="form-group">
<label class="col-sm-3">Url</label>
<span class="col-sm-9"><input name="url" type="url" placeholder="url" class="form-control" data-minlength="3" required="required"/></span>
</div>
<br/><br/>
<div class="form-group">
<label class="col-sm-3">Subreddit</label>
<span class="col-sm-9"><input id="sr" name="sr" placeholder="Subreddit (e.g. kitten)" class="form-control" data-minlength="3" required="required"/></span>
</div>
<br/><br/>
<div>
<label class="col-sm-3">Send replies to my inbox</label>
<span class="col-sm-9"><input type="checkbox" name="sendreplies" value="true"/></span>
</div>
<br/>
<br/>
<div>
<span class="col-sm-2"><a href="#" class="btn btn-default" onclick="checkIfAlreadySubmitted()">Check if already submitted</a></span>
<span class="col-sm-1"></span>
<span class=" col-sm-9"><span id="checkResult" class="alert alert-info" style="display:none"></span></span>
</div>
<br/><br/>
<div th:if="${iden != null}">
<input type="hidden" name="iden" value="${iden}"/>
<div class="form-group">
<label class="col-sm-3">Captcha</label>
<span class="col-sm-9"><input name="captcha" placeholder="captcha" class="form-control"/></span>
</div>
<br/><br/>
<img src="http://www.reddit.com/captcha/${iden}" alt="captcha" width="200"/>
</div>
<br/><br/>
<span class="col-sm-3"><button id="submitbtn" type="submit" class="btn btn-primary">Post</button></span>
</div>
</form>
<div>
<div th:if="${session.PREDICTION_FEATURE.isActive()}">
<button id="checkbtn" class="btn btn-default disabled" onclick="predicateResponse()">Predicate Response</button>
<span id="prediction"></span>
<script type="text/javascript">
/*<![CDATA[*/
$("input").change(function() {
if($("#submitbtn").hasClass("disabled")){
if(! $("#checkbtn").hasClass("disabled")){
$("#checkbtn").addClass("disabled");
}
}else{
$("#checkbtn").removeClass("disabled");
}
});
function predicateResponse(){
var title = $('input[name="title"]').val();
var domain = $('input[name="url"]').val();
domain = $('<a>').prop('href', domain).prop('hostname');
console.log(domain);
$.post("predicatePostResponse",{title: title, domain: domain} ,function(data){
$("#prediction").addClass("alert alert-info").html(data.replace('{','').replace('}',''));
});
}
/*]]>*/
</script>
</div>
</div>
</div>
<script>
$(function() {
$( "#sr" ).autocomplete({
source: "subredditAutoComplete"
});
$("input[name='url'],input[name='sr']").focus(function (){
$("#checkResult").hide();
});
});
</script>
<script>
/*<![CDATA[*/
function checkIfAlreadySubmitted(){
var url = $("input[name='url']").val();
var sr = $("input[name='sr']").val();
console.log(url);
if(url.length >3 && sr.length > 3){
$.post("checkIfAlreadySubmitted",{url: url, sr: sr}, function(data){
var result = JSON.parse(data);
if(result.length == 0){
$("#checkResult").show().html("Not submitted before");
}else{
$("#checkResult").show().html('Already submitted <b><a target="_blank" href="http://www.reddit.com'+result[0].data.permalink+'">here</a></b>');
}
});
}
else{
$("#checkResult").show().html("Too short url and/or subreddit");
}
}
/*]]>*/
</script>
</body>
</html>

View File

@ -1,14 +0,0 @@
<html>
<head>
<title>Schedule to Reddit</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"/>
</head>
<body>
<div th:include="header"/>
<div class="container">
<h1 th:text="${msg}">Hello</h1>
</div>
</body>
</html>

View File

@ -1,14 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Schedule to Reddit</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"/>
</head>
<body>
<div class="container">
<h1>Schedule to Reddit</h1>
<a href="login" class="btn btn-primary">Login with Reddit</a>
</div>
</body>
</html>

View File

@ -1,25 +0,0 @@
.ui-autocomplete {
position: absolute;
z-index: 1000;
cursor: default;
padding: 0;
margin-top: 2px;
list-style: none;
background-color: #ffffff;
border: 1px solid #ccc
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
}
.ui-autocomplete > li {
padding: 3px 20px;
}
.ui-autocomplete > li.ui-state-focus {
background-color: #DDD;
}
.ui-helper-hidden-accessible {
display: none;
}

View File

@ -1,332 +0,0 @@
/**
* Style-sheet for dtpicker
* https://github.com/mugifly/jquery-simple-datetimepicker
*/
.datepicker {
position: relative;
display: inline-block;
font: 15px/1.5 "Helvetica Neue", mplus-2c, Helvetica, Arial, "Hiragino Kaku Gothic Pro", Meiryo, sans-serif;
font-weight: 300;
border: 1px solid #dfdfdf;
border-radius: 3px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
box-shadow: 0.5px 0.5px 0px #c8c8c8;
-webkit-box-shadow: 0.5px 0.5px 3px #eeeeee;
-moz-box-shadow: 0.5px 0.5px 3px #eeeeee;
}
/*
* datepicker_header
*/
.datepicker > .datepicker_header{
padding-top: 2px;
padding-bottom: 2px;
padding-left: 5px;
padding-right: 5px;
background-color: #eeeeee;
color: #3f3f3f;
text-align: center;
font-size: 9pt;
font-weight: bold;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
}
.datepicker > .datepicker_header > a {
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
cursor: pointer;
color: #3b7796;
padding: 3px 16px;
font-size: 20px;
}
.datepicker > .datepicker_header > a:hover {
color: #303030;
background-color: #c8c8c8;
}
.datepicker > .datepicker_header > a:active {
color: #ffffff;
background-color: #808080;
}
.datepicker > .datepicker_header > span {
margin-left: 20px;
margin-right: 20px;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
}
.datepicker > .datepicker_header > .icon-home {
position: absolute;
display: block;
width: 16px;
height: 16px;
vertical-align: middle;
padding: 8px;
top: 0;
left: 0;
}
.datepicker > .datepicker_header > .icon-close {
position: absolute;
display: block;
width: 16px;
height: 16px;
vertical-align: middle;
padding: 8px;
top: 0;
right: 0;
}
.datepicker > .datepicker_header > .icon-home > div {
width: 16px;
height: 16px;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAQCAYAAAB3AH1ZAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAepJREFUSEudk71Kw2AUhnVxVnCyN1EcCjXUujmKF1AoRRCcNU4OIg5dtXF36tAb6B107qjg0iC4STt0EdTnTU8+v5rGNh54aM7Pe/J+abLmR3AZ7QeXD0+WZkI9zViaiXq9vg+5evU0Y+ksgjCqsrgPA2jBOzQs91FNPc0o70vLQtGHAbTgHRqW+6imnmaUS1PVqWL4SgijJr8juHK1H1Qb2Uxai1kivowmjODKq6Wopp5m0losA95Noh43ONXi+XpCPOsx49W9ZaIHp+CbSlFNPc24+i8DxfGX/YeZgTDqQrsgXc9AF9oFkcY9gQN7J3MjuOhs2WUS0ngGluqZmdNLs7IBTltmZsrvsZUKGaBfhik4vTSw3EBwfrdBfwhvwcX9tpVXNkBvA4bwBk4vDSw2UD27WbdLnf42mQmjIysl8ZeBWq3m9PRubWZOL43qGQOccpf8lc9tj5tWuP7g+tHaLqSR1pY7Pde78Ap7UIEPyOip5RgIOzvkzzCGF4gxtWltF9LAIgM78AxjeAF9/xk9tfy/gBuWOLVMfPIUDq08F3kGFOQlkIlPWKiXBvJfQl6+EjdvWJqJvwwoqMlErl4aabVowmmvbWEBEs2EJeLaFhZBmone8hMtAj2JIkykZYmQifRprAqa+sk3UgBXF8VWaxMAAAAASUVORK5CYII=);
}
.datepicker > .datepicker_header > .icon-close> div {
width: 16px;
height: 16px;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAQCAYAAAB3AH1ZAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAfhJREFUSEvNVEtKA0EUHHBhsvZ7D0HF4PRMnERxI+hCQ4xuBE/g5yLRA+il/CCIXkDElRGt6qkZO91j1JUW1KJf1XvVn2Gif4XGUX986aRf0zIANXq0DBBv7Iwvb+192U+NHi2H0Tg+O2ycnN2DV+CcyiVQW5B2T6/KJUxr7dAkySN4bVbaiyqXMM1s3mr0wKtyDgytgQ/gu/gKbkumvgsOpJH0lieNN3s1O9iYd/EN657kyJikZ2uFDi97JDOgX8fAWyeg2MQO6IeT8Pbrao+Wtw/qJklvywBnE5ZuOAkve9SeA0PnQT+Ia7/2BoZXnK0uBkH5Oqxl4RNZYHAH9ANdMnxP9gA42X5FoMuhp6kEAnjlDPpVeIERm0B4+m0/N9AFq26Bta5sX0JvPvDCycFPTs+PbtQTUOvIHgAhu+DoJ4BH9mFgcAzyy3cDee3+c9ATq60ErjfDcP/kDPQ3hJtIM7XlwMAJ8FoBBe2bi/4m6J1QO34yrWlc740XxDffr/wm6EWP2u0GJsEnDS/DJVPvge7T0DspmT+aGQx+cUKGPriKTcCbzEhGwOn5GAZegM/gHdiSVAK1VBo9F+yRFJn2+hgGXtrBSXpn0mbQb5orbavl4ZfskZRDm5gGp1QKQM16nPACdhNpczZur3+ezAM1eoLwv0MUfQBkquZISGUUwgAAAABJRU5ErkJggg==);
}
.datepicker > .datepicker_header > a:hover > div, .datepicker > .datepicker_header > a:hover > div {
background-position: -16px 0px;
}
/*
* datepicker_inner_container
*/
.datepicker > .datepicker_inner_container {
margin: -2px 0px -2px 0px;
background-color: #d2d2d2;
border: 1px solid #c8c8c8;
border-radius: 3px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
box-shadow: 0.5px 0px 3px #c8c8c8;
-webkit-box-shadow: 0.5px 0px 3px #c8c8c8;
-moz-box-shadow: 0.5px 0px 3px #c8c8c8;
}
.datepicker > .datepicker_inner_container:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
/*
* datepicker_inner_container > datepicker_calendar
*/
.datepicker > .datepicker_inner_container > .datepicker_calendar {
float: left;
width: 18.3em;
margin-top: -0.5px;
margin-left: -1px;
margin-bottom: -2px;
background-color: #ffffff;
border: 1px solid #c8c8c8;
border-top:none;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
-webkit-border-top-left-radius: 3px;
-webkit-border-bottom-left-radius: 3px;
-moz-border-radius-topleft: 3px;
-moz-border-radius-bottomleft: 3px;
}
.datepicker > .datepicker_inner_container > .datepicker_calendar > table {
padding: 10px;
}
/*
* datepicker_inner_container > datepicker_calendar > datepicker_table > tbody > tr > th (WDay-cell)
*/
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > th {
color: #646464;
width: 18px;
font-size: small;
font-weight: normal;
text-align:center;
}
/*
* datepicker_inner_container > datepicker_calendar > datepicker_table > tbody > tr > td (Day-cell)
*/
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td {
color: #000000;
font-size: small;
text-align:center;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
cursor: pointer;
padding: 10px;
}
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.today {
border-bottom: #bfbfbf solid 2px;
margin-bottom: -2px;
}
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.wday_sat {
color: #0044aa;
}
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.wday_sun {
color: #e13b00;
}
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.day_another_month {
color: #cccccc;
}
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.day_in_past {
cursor: default;
color: #cccccc;
}
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.day_in_unallowed {
cursor: default;
color: #cccccc;
}
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.out_of_range {
cursor: default;
color: #cccccc;
}
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.active {
color: #ffffff;
background-color: #808080;
}
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.hover {
color: #000000;
background-color: #c8c8c8;
}
/*
* datepicker_inner_container > datepicker_timelist
*/
.datepicker > .datepicker_inner_container > .datepicker_timelist {
float: left;
margin-top: -0.5px;
padding: 5px 0px;
overflow: auto;
overflow-x: hidden;
background-color: #ffffff;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
-webkit-border-top-right-radius: 3px;
-webkit-border-bottom-right-radius: 3px;
-moz-border-radius-topright: 3px;
-moz-border-radius-bottomright: 3px;
text-align: right;
width: 4.9em;
}
/*
.datepicker > .datepicker_inner_container > .datepicker_timelist::after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
*/
.datepicker > .datepicker_inner_container > .datepicker_timelist::-webkit-scrollbar {
overflow: hidden;
width: 6px;
background: #fafafa;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
-webkit-border-top-right-radius: 3px;
-webkit-border-bottom-right-radius: 3px;
-moz-border-radius-topright: 3px;
-moz-border-radius-bottomright: 3px;
}
.datepicker > .datepicker_inner_container > .datepicker_timelist::-webkit-scrollbar:horizontal {
height: 1px;
}
.datepicker > .datepicker_inner_container > .datepicker_timelist::-webkit-scrollbar-button {
display: none;
}
.datepicker > .datepicker_inner_container > .datepicker_timelist::-webkit-scrollbar-piece {
background: #eee;
}
.datepicker > .datepicker_inner_container > .datepicker_timelist::-webkit-scrollbar-piece:start {
background: #eee;
}
.datepicker > .datepicker_inner_container > .datepicker_timelist::-webkit-scrollbar-thumb {
background: #aaaaaa;
border-radius: 3px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
}
.datepicker > .datepicker_inner_container > .datepicker_timelist::-webkit-scrollbar-corner {
background: #333;
}
.datepicker > .datepicker_inner_container > .datepicker_timelist > div.timelist_item {
padding-top: 5px;
padding-bottom:5px;
padding-left: 7px;
padding-right: 7px;
margin-top: 5px;
margin-bottom: 2px;
font-size: small;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
cursor: pointer;
}
.datepicker > .datepicker_inner_container > .datepicker_timelist > div.timelist_item.time_in_past {
cursor: default;
color: #cccccc;
}
.datepicker > .datepicker_inner_container > .datepicker_timelist > div.timelist_item.out_of_range {
cursor: default;
color: #cccccc;
}
.datepicker > .datepicker_inner_container > .datepicker_timelist > div.timelist_item.active {
color: #ffffff;
background-color: #808080;
}
.datepicker > .datepicker_inner_container > .datepicker_timelist > div.timelist_item.hover {
color: #000000;
background-color: #c8c8c8;
}

View File

@ -1,304 +0,0 @@
/* ========================================================================
* Bootstrap (plugin): validator.js v0.7.2
* ========================================================================
* The MIT License (MIT)
*
* Copyright (c) 2013 Cina Saffary.
* Made by @1000hz in the style of Bootstrap 3 era @fat
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
* ======================================================================== */
+function ($) {
'use strict';
// VALIDATOR CLASS DEFINITION
// ==========================
var Validator = function (element, options) {
this.$element = $(element)
this.options = options
this.$element.attr('novalidate', true) // disable automatic native validation
this.toggleSubmit()
this.$element.on('input.bs.validator change.bs.validator focusout.bs.validator', $.proxy(this.validateInput, this))
this.$element.on('submit.bs.validator', $.proxy(this.onSubmit, this))
this.$element.find('[data-match]').each(function () {
var $this = $(this)
var target = $this.data('match')
$(target).on('input.bs.validator', function (e) {
$this.val() && $this.trigger('input.bs.validator')
})
})
}
Validator.DEFAULTS = {
delay: 500,
html: false,
disable: true,
errors: {
match: 'Does not match',
minlength: 'Not long enough'
}
}
Validator.VALIDATORS = {
native: function ($el) {
var el = $el[0]
return el.checkValidity ? el.checkValidity() : true
},
match: function ($el) {
var target = $el.data('match')
return !$el.val() || $el.val() === $(target).val()
},
minlength: function ($el) {
var minlength = $el.data('minlength')
return !$el.val() || $el.val().length >= minlength
}
}
Validator.prototype.validateInput = function (e) {
var $el = $(e.target)
var prevErrors = $el.data('bs.validator.errors')
var errors
if ($el.is('[type="radio"]')) $el = this.$element.find('input[name="' + $el.attr('name') + '"]')
this.$element.trigger(e = $.Event('validate.bs.validator', {relatedTarget: $el[0]}))
if (e.isDefaultPrevented()) return
var self = this
this.runValidators($el).done(function (errors) {
$el.data('bs.validator.errors', errors)
errors.length ? self.showErrors($el) : self.clearErrors($el)
if (!prevErrors || errors.toString() !== prevErrors.toString()) {
e = errors.length
? $.Event('invalid.bs.validator', {relatedTarget: $el[0], detail: errors})
: $.Event('valid.bs.validator', {relatedTarget: $el[0], detail: prevErrors})
self.$element.trigger(e)
}
self.toggleSubmit()
self.$element.trigger($.Event('validated.bs.validator', {relatedTarget: $el[0]}))
})
}
Validator.prototype.runValidators = function ($el) {
var errors = []
var validators = [Validator.VALIDATORS.native]
var deferred = $.Deferred()
var options = this.options
$el.data('bs.validator.deferred') && $el.data('bs.validator.deferred').reject()
$el.data('bs.validator.deferred', deferred)
function getErrorMessage(key) {
return $el.data(key + '-error')
|| $el.data('error')
|| key == 'native' && $el[0].validationMessage
|| options.errors[key]
}
$.each(Validator.VALIDATORS, $.proxy(function (key, validator) {
if (($el.data(key) || key == 'native') && !validator.call(this, $el)) {
var error = getErrorMessage(key)
!~errors.indexOf(error) && errors.push(error)
}
}, this))
if (!errors.length && $el.val() && $el.data('remote')) {
this.defer($el, function () {
var data = {}
data[$el.attr('name')] = $el.val()
$.get($el.data('remote'), data)
.fail(function (jqXHR, textStatus, error) { errors.push(getErrorMessage('remote') || error) })
.always(function () { deferred.resolve(errors)})
})
} else deferred.resolve(errors)
return deferred.promise()
}
Validator.prototype.validate = function () {
var delay = this.options.delay
this.options.delay = 0
this.$element.find(':input').trigger('input.bs.validator')
this.options.delay = delay
return this
}
Validator.prototype.showErrors = function ($el) {
var method = this.options.html ? 'html' : 'text'
this.defer($el, function () {
var $group = $el.closest('.form-group')
var $block = $group.find('.help-block.with-errors')
var $feedback = $group.find('.form-control-feedback')
var errors = $el.data('bs.validator.errors')
if (!errors.length) return
errors = $('<ul/>')
.addClass('list-unstyled')
.append($.map(errors, function (error) { return $('<li/>')[method](error) }))
$block.data('bs.validator.originalContent') === undefined && $block.data('bs.validator.originalContent', $block.html())
$block.empty().append(errors)
$group.removeClass('has-success')
$group.addClass('has-error')
$feedback.removeClass('glyphicon-ok')
$feedback.addClass('glyphicon-warning-sign')
})
}
Validator.prototype.clearErrors = function ($el) {
var $group = $el.closest('.form-group')
var $block = $group.find('.help-block.with-errors')
var $feedback = $group.find('.form-control-feedback')
$block.html($block.data('bs.validator.originalContent'))
$group.removeClass('has-error')
$group.addClass('has-success')
$feedback.removeClass('glyphicon-warning-sign')
$feedback.addClass('glyphicon-ok')
}
Validator.prototype.hasErrors = function () {
function fieldErrors() {
return !!($(this).data('bs.validator.errors') || []).length
}
return !!this.$element.find(':input:enabled').filter(fieldErrors).length
}
Validator.prototype.isIncomplete = function () {
function fieldIncomplete() {
return this.type === 'checkbox' ? !this.checked :
this.type === 'radio' ? !$('[name="' + this.name + '"]:checked').length :
$.trim(this.value) === ''
}
return !!this.$element.find(':input[required]:enabled').filter(fieldIncomplete).length
}
Validator.prototype.onSubmit = function (e) {
this.validate()
if (this.isIncomplete() || this.hasErrors()) e.preventDefault()
}
Validator.prototype.toggleSubmit = function () {
if(!this.options.disable) return
var $btn = this.$element.find('input[type="submit"], button[type="submit"]')
$btn.toggleClass('disabled', this.isIncomplete() || this.hasErrors())
.css({'pointer-events': 'all', 'cursor': 'pointer'})
}
Validator.prototype.defer = function ($el, callback) {
if (!this.options.delay) return callback()
window.clearTimeout($el.data('bs.validator.timeout'))
$el.data('bs.validator.timeout', window.setTimeout(callback, this.options.delay))
}
Validator.prototype.destroy = function () {
this.$element
.removeAttr('novalidate')
.removeData('bs.validator')
.off('.bs.validator')
this.$element.find(':input')
.off('.bs.validator')
.removeData(['bs.validator.errors', 'bs.validator.deferred'])
.each(function () {
var $this = $(this)
var timeout = $this.data('bs.validator.timeout')
window.clearTimeout(timeout) && $this.removeData('bs.validator.timeout')
})
this.$element.find('.help-block.with-errors').each(function () {
var $this = $(this)
var originalContent = $this.data('bs.validator.originalContent')
$this
.removeData('bs.validator.originalContent')
.html(originalContent)
})
this.$element.find('input[type="submit"], button[type="submit"]').removeClass('disabled')
this.$element.find('.has-error').removeClass('has-error')
return this
}
// VALIDATOR PLUGIN DEFINITION
// ===========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var options = $.extend({}, Validator.DEFAULTS, $this.data(), typeof option == 'object' && option)
var data = $this.data('bs.validator')
if (!data && option == 'destroy') return
if (!data) $this.data('bs.validator', (data = new Validator(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.validator
$.fn.validator = Plugin
$.fn.validator.Constructor = Validator
// VALIDATOR NO CONFLICT
// =====================
$.fn.validator.noConflict = function () {
$.fn.validator = old
return this
}
// VALIDATOR DATA-API
// ==================
$(window).on('load', function () {
$('form[data-toggle="validator"]').each(function () {
var $form = $(this)
Plugin.call($form, $form.data())
})
})
}(jQuery);

View File

@ -1,44 +0,0 @@
package org.baeldung.classifier;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import org.baeldung.reddit.classifier.RedditClassifier;
import org.baeldung.reddit.classifier.RedditDataCollector;
import org.junit.Ignore;
import org.junit.Test;
@Ignore
public class RedditClassifierTest {
@Test
public void whenUsingDefaultClassifier_thenAccurate() throws IOException {
final RedditClassifier classifier = new RedditClassifier();
classifier.trainClassifier(RedditDataCollector.DATA_FILE);
final double result = classifier.getAccuracy();
System.out.println("==== Default Classifier Accuracy = " + result);
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++\n\n\n");
assertTrue(result > 0.7);
}
@Test
public void givenSmallerPoolSizeAndFeatures_whenUsingCustomClassifier_thenAccurate() throws IOException {
final RedditClassifier classifier = new RedditClassifier(100, 500, 7);
classifier.trainClassifier(RedditDataCollector.DATA_FILE);
final double result = classifier.getAccuracy();
System.out.println("==== Custom Classifier (small) Accuracy = " + result);
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++\n\n\n");
assertTrue(result < 0.7);
}
@Test
public void givenLargerPoolSizeAndFeatures_whenUsingCustomClassifier_thenAccurate() throws IOException {
final RedditClassifier classifier = new RedditClassifier(250, 2500, 7);
classifier.trainClassifier(RedditDataCollector.DATA_FILE);
final double result = classifier.getAccuracy();
System.out.println("==== Custom Classifier (large) Accuracy = " + result);
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++\n\n\n");
assertTrue(result > 0.7);
}
}

View File

@ -1,106 +0,0 @@
package org.baeldung.persistence;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.IsIn.isIn;
import static org.hamcrest.core.IsNot.not;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import org.baeldung.persistence.dao.PostRepository;
import org.baeldung.persistence.dao.UserRepository;
import org.baeldung.persistence.model.Post;
import org.baeldung.persistence.model.User;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestJPAConfig.class })
@Transactional
@TransactionConfiguration
// @Ignore
public class PersistenceJPATest {
@Autowired
private PostRepository postRepository;
@Autowired
private UserRepository userRepository;
private Post alreadySentPost, notSentYetOld, notSentYet;
private User userJohn, userTom;
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
@Before
public void init() throws ParseException {
userJohn = new User();
userJohn.setUsername("John");
userRepository.save(userJohn);
userTom = new User();
userTom.setUsername("Tom");
userRepository.save(userTom);
alreadySentPost = new Post();
alreadySentPost.setTitle("First post title");
alreadySentPost.setSent(true);
alreadySentPost.setSubmissionDate(dateFormat.parse("2015-03-03 10:30"));
alreadySentPost.setUser(userJohn);
alreadySentPost.setSubreddit("funny");
alreadySentPost.setUrl("www.example.com");
postRepository.save(alreadySentPost);
notSentYetOld = new Post();
notSentYetOld.setTitle("Second post title");
notSentYetOld.setSent(false);
notSentYetOld.setSubmissionDate(dateFormat.parse("2015-03-03 11:00"));
notSentYetOld.setUser(userTom);
notSentYetOld.setSubreddit("funny");
notSentYetOld.setUrl("www.example.com");
postRepository.save(notSentYetOld);
notSentYet = new Post();
notSentYet.setTitle("Second post title");
notSentYet.setSent(false);
notSentYet.setSubmissionDate(dateFormat.parse("2015-03-03 11:30"));
notSentYet.setUser(userJohn);
notSentYet.setSubreddit("funny");
notSentYet.setUrl("www.example.com");
postRepository.save(notSentYet);
}
@Test
public void whenGettingListOfSentPosts_thenCorrect() throws ParseException {
final List<Post> results = postRepository.findBySubmissionDateBeforeAndIsSent(dateFormat.parse("2015-03-03 11:50"), true);
assertThat(alreadySentPost, isIn(results));
assertThat(notSentYet, not(isIn(results)));
assertThat(notSentYetOld, not(isIn(results)));
}
@Test
public void whenGettingListOfOldPosts_thenCorrect() throws ParseException {
final List<Post> results = postRepository.findBySubmissionDateBeforeAndIsSent(dateFormat.parse("2015-03-03 11:01"), false);
assertThat(notSentYetOld, isIn(results));
assertThat(notSentYet, not(isIn(results)));
assertThat(alreadySentPost, not(isIn(results)));
}
@Test
public void whenGettingListOfSpecificuser_thenCorrect() throws ParseException {
final List<Post> results = postRepository.findByUser(userTom);
assertThat(notSentYetOld, isIn(results));
assertThat(notSentYet, not(isIn(results)));
assertThat(alreadySentPost, not(isIn(results)));
}
}

View File

@ -1,73 +0,0 @@
package org.baeldung.persistence;
import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@PropertySource({ "classpath:persistence-test.properties" })
@ComponentScan({ "org.baeldung.persistence.model", "org.baeldung.persistence.dao" })
@EnableJpaRepositories(basePackages = "org.baeldung.persistence.dao")
public class TestJPAConfig {
@Autowired
private Environment env;
public TestJPAConfig() {
super();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "org.baeldung.persistence.model" });
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
@Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.user"));
dataSource.setPassword(env.getProperty("jdbc.pass"));
return dataSource;
}
@Bean
public JpaTransactionManager transactionManager() {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
final Properties additionalProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto", "create-drop"));
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
return hibernateProperties;
}
}

View File

@ -1,4 +0,0 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore