Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
라이앤캐처스 크루공간
허창호
연습용
Commits
969fb9e8
Commit
969fb9e8
authored
Feb 06, 2022
by
madvirus
Browse files
Initial Commit
parents
Changes
187
Hide whitespace changes
Inline
Side-by-side
src/main/java/com/myshop/integration/infra/MemoryOffsetStore.java
0 → 100644
View file @
969fb9e8
package
com.myshop.integration.infra
;
import
com.myshop.integration.OffsetStore
;
import
org.springframework.stereotype.Component
;
@Component
public
class
MemoryOffsetStore
implements
OffsetStore
{
private
long
nextOffset
=
0
;
@Override
public
long
get
()
{
return
nextOffset
;
}
@Override
public
void
update
(
long
nextOffset
)
{
this
.
nextOffset
=
nextOffset
;
}
}
src/main/java/com/myshop/integration/infra/SysoutEventSender.java
0 → 100644
View file @
969fb9e8
package
com.myshop.integration.infra
;
import
com.myshop.eventstore.api.EventEntry
;
import
com.myshop.integration.EventSender
;
import
org.springframework.stereotype.Component
;
@Component
public
class
SysoutEventSender
implements
EventSender
{
@Override
public
void
send
(
EventEntry
event
)
{
System
.
out
.
println
(
"EventSender send event : "
+
event
);
}
}
src/main/java/com/myshop/lock/AlreadyLockedException.java
0 → 100644
View file @
969fb9e8
package
com.myshop.lock
;
public
class
AlreadyLockedException
extends
LockException
{
}
src/main/java/com/myshop/lock/LockData.java
0 → 100644
View file @
969fb9e8
package
com.myshop.lock
;
public
class
LockData
{
private
String
type
;
private
String
id
;
private
String
lockId
;
private
long
timestamp
;
public
LockData
(
String
type
,
String
id
,
String
lockId
,
long
timestamp
)
{
this
.
type
=
type
;
this
.
id
=
id
;
this
.
lockId
=
lockId
;
this
.
timestamp
=
timestamp
;
}
public
String
getType
()
{
return
type
;
}
public
String
getId
()
{
return
id
;
}
public
String
getLockId
()
{
return
lockId
;
}
public
long
getTimestamp
()
{
return
timestamp
;
}
public
boolean
isExpired
()
{
return
timestamp
<
System
.
currentTimeMillis
();
}
}
\ No newline at end of file
src/main/java/com/myshop/lock/LockException.java
0 → 100644
View file @
969fb9e8
package
com.myshop.lock
;
public
class
LockException
extends
RuntimeException
{
public
LockException
()
{
}
public
LockException
(
String
message
)
{
super
(
message
);
}
public
LockException
(
Throwable
cause
)
{
super
(
cause
);
}
}
src/main/java/com/myshop/lock/LockId.java
0 → 100644
View file @
969fb9e8
package
com.myshop.lock
;
public
class
LockId
{
private
String
value
;
public
LockId
(
String
value
)
{
this
.
value
=
value
;
}
public
String
getValue
()
{
return
value
;
}
}
src/main/java/com/myshop/lock/LockManager.java
0 → 100644
View file @
969fb9e8
package
com.myshop.lock
;
public
interface
LockManager
{
LockId
tryLock
(
String
type
,
String
id
)
throws
LockException
;
void
checkLock
(
LockId
lockId
)
throws
LockException
;
void
releaseLock
(
LockId
lockId
)
throws
LockException
;
void
extendLockExpiration
(
LockId
lockId
,
long
inc
)
throws
LockException
;
}
src/main/java/com/myshop/lock/LockManagerException.java
0 → 100644
View file @
969fb9e8
package
com.myshop.lock
;
public
class
LockManagerException
extends
RuntimeException
{
public
LockManagerException
(
Exception
cause
)
{
super
(
cause
);
}
}
src/main/java/com/myshop/lock/LockingFailException.java
0 → 100644
View file @
969fb9e8
package
com.myshop.lock
;
public
class
LockingFailException
extends
LockException
{
public
LockingFailException
()
{
}
public
LockingFailException
(
Exception
cause
)
{
super
(
cause
);
}
}
src/main/java/com/myshop/lock/NoLockException.java
0 → 100644
View file @
969fb9e8
package
com.myshop.lock
;
public
class
NoLockException
extends
RuntimeException
{
}
src/main/java/com/myshop/lock/SpringLockManager.java
0 → 100644
View file @
969fb9e8
package
com.myshop.lock
;
import
org.springframework.dao.DuplicateKeyException
;
import
org.springframework.jdbc.core.JdbcTemplate
;
import
org.springframework.jdbc.core.RowMapper
;
import
org.springframework.stereotype.Component
;
import
org.springframework.transaction.annotation.Propagation
;
import
org.springframework.transaction.annotation.Transactional
;
import
java.sql.Timestamp
;
import
java.util.List
;
import
java.util.Optional
;
import
java.util.UUID
;
@Component
public
class
SpringLockManager
implements
LockManager
{
private
int
lockTimeout
=
5
*
60
*
1000
;
private
JdbcTemplate
jdbcTemplate
;
private
RowMapper
<
LockData
>
lockDataRowMapper
=
(
rs
,
rowNum
)
->
new
LockData
(
rs
.
getString
(
1
),
rs
.
getString
(
2
),
rs
.
getString
(
3
),
rs
.
getTimestamp
(
4
).
getTime
());
public
SpringLockManager
(
JdbcTemplate
jdbcTemplate
)
{
this
.
jdbcTemplate
=
jdbcTemplate
;
}
@Transactional
(
propagation
=
Propagation
.
REQUIRES_NEW
)
@Override
public
LockId
tryLock
(
String
type
,
String
id
)
throws
LockException
{
checkAlreadyLocked
(
type
,
id
);
LockId
lockId
=
new
LockId
(
UUID
.
randomUUID
().
toString
());
locking
(
type
,
id
,
lockId
);
return
lockId
;
}
private
void
checkAlreadyLocked
(
String
type
,
String
id
)
{
List
<
LockData
>
locks
=
jdbcTemplate
.
query
(
"select * from locks where type = ? and id = ?"
,
lockDataRowMapper
,
type
,
id
);
Optional
<
LockData
>
lockData
=
handleExpiration
(
locks
);
if
(
lockData
.
isPresent
())
throw
new
AlreadyLockedException
();
}
private
Optional
<
LockData
>
handleExpiration
(
List
<
LockData
>
locks
)
{
if
(
locks
.
isEmpty
())
return
Optional
.
empty
();
LockData
lockData
=
locks
.
get
(
0
);
if
(
lockData
.
isExpired
())
{
jdbcTemplate
.
update
(
"delete from locks where type = ? and id = ?"
,
lockData
.
getType
(),
lockData
.
getId
());
return
Optional
.
empty
();
}
else
{
return
Optional
.
of
(
lockData
);
}
}
private
void
locking
(
String
type
,
String
id
,
LockId
lockId
)
{
try
{
int
updatedCount
=
jdbcTemplate
.
update
(
"insert into locks values (?, ?, ?, ?)"
,
type
,
id
,
lockId
.
getValue
(),
new
Timestamp
(
getExpirationTime
()));
if
(
updatedCount
==
0
)
throw
new
LockingFailException
();
}
catch
(
DuplicateKeyException
e
)
{
throw
new
LockingFailException
(
e
);
}
}
private
long
getExpirationTime
()
{
return
System
.
currentTimeMillis
()
+
lockTimeout
;
}
@Transactional
(
propagation
=
Propagation
.
REQUIRES_NEW
)
@Override
public
void
checkLock
(
LockId
lockId
)
throws
LockException
{
Optional
<
LockData
>
lockData
=
getLockData
(
lockId
);
if
(!
lockData
.
isPresent
())
throw
new
NoLockException
();
}
private
Optional
<
LockData
>
getLockData
(
LockId
lockId
)
{
List
<
LockData
>
locks
=
jdbcTemplate
.
query
(
"select * from locks where lockid = ?"
,
lockDataRowMapper
,
lockId
.
getValue
());
return
handleExpiration
(
locks
);
}
@Transactional
(
propagation
=
Propagation
.
REQUIRES_NEW
)
@Override
public
void
extendLockExpiration
(
LockId
lockId
,
long
inc
)
throws
LockException
{
Optional
<
LockData
>
lockDataOpt
=
getLockData
(
lockId
);
LockData
lockData
=
lockDataOpt
.
orElseThrow
(()
->
new
NoLockException
());
jdbcTemplate
.
update
(
"update locks set expiration_time = ? where type = ? AND id = ?"
,
new
Timestamp
(
lockData
.
getTimestamp
()
+
inc
),
lockData
.
getType
(),
lockData
.
getId
());
}
@Transactional
(
propagation
=
Propagation
.
REQUIRES_NEW
)
@Override
public
void
releaseLock
(
LockId
lockId
)
throws
LockException
{
jdbcTemplate
.
update
(
"delete from locks where lockid = ?"
,
lockId
.
getValue
());
}
public
void
setLockTimeout
(
int
lockTimeout
)
{
this
.
lockTimeout
=
lockTimeout
;
}
}
\ No newline at end of file
src/main/java/com/myshop/member/command/application/BlockMemberService.java
0 → 100644
View file @
969fb9e8
package
com.myshop.member.command.application
;
import
com.myshop.member.command.domain.Member
;
import
com.myshop.member.command.domain.MemberId
;
import
com.myshop.member.command.domain.MemberRepository
;
import
org.springframework.security.access.prepost.PreAuthorize
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
@Service
public
class
BlockMemberService
{
private
MemberRepository
memberRepository
;
public
BlockMemberService
(
MemberRepository
memberRepository
)
{
this
.
memberRepository
=
memberRepository
;
}
@PreAuthorize
(
"hasRole('ADMIN')"
)
@Transactional
public
void
block
(
String
memberId
)
{
Member
member
=
memberRepository
.
findById
(
new
MemberId
(
memberId
))
.
orElseThrow
(()
->
new
NoMemberException
());
member
.
block
();
}
}
src/main/java/com/myshop/member/command/application/NoMemberException.java
0 → 100644
View file @
969fb9e8
package
com.myshop.member.command.application
;
public
class
NoMemberException
extends
RuntimeException
{
}
src/main/java/com/myshop/member/command/domain/IdPasswordNotMatchingException.java
0 → 100644
View file @
969fb9e8
package
com.myshop.member.command.domain
;
public
class
IdPasswordNotMatchingException
extends
RuntimeException
{
}
src/main/java/com/myshop/member/command/domain/Member.java
0 → 100644
View file @
969fb9e8
package
com.myshop.member.command.domain
;
import
com.myshop.common.event.Events
;
import
com.myshop.common.jpa.EmailSetConverter
;
import
com.myshop.common.model.Email
;
import
com.myshop.common.model.EmailSet
;
import
javax.persistence.*
;
import
java.util.Random
;
import
java.util.Set
;
@Entity
@Table
(
name
=
"member"
)
public
class
Member
{
@EmbeddedId
private
MemberId
id
;
private
String
name
;
@Embedded
private
Password
password
;
private
boolean
blocked
;
@Column
(
name
=
"emails"
)
@Convert
(
converter
=
EmailSetConverter
.
class
)
private
EmailSet
emails
;
protected
Member
()
{
}
public
Member
(
MemberId
id
,
String
name
)
{
this
.
id
=
id
;
this
.
name
=
name
;
}
public
MemberId
getId
()
{
return
id
;
}
public
String
getName
()
{
return
name
;
}
public
void
initializePassword
()
{
String
newPassword
=
generateRandomPassword
();
this
.
password
=
new
Password
(
newPassword
);
Events
.
raise
(
new
PasswordChangedEvent
(
id
.
getId
(),
newPassword
));
}
private
String
generateRandomPassword
()
{
Random
random
=
new
Random
();
int
number
=
random
.
nextInt
();
return
Integer
.
toHexString
(
number
);
}
public
void
changeEmails
(
Set
<
Email
>
emails
)
{
this
.
emails
=
new
EmailSet
(
emails
);
}
public
void
block
()
{
this
.
blocked
=
true
;
Events
.
raise
(
new
MemberBlockedEvent
(
id
.
getId
()));
}
public
void
unblock
()
{
this
.
blocked
=
false
;
Events
.
raise
(
new
MemberUnblockedEvent
(
id
.
getId
()));
}
public
void
changePassword
(
String
oldPw
,
String
newPw
)
{
if
(!
password
.
match
(
oldPw
))
{
throw
new
IdPasswordNotMatchingException
();
}
this
.
password
=
new
Password
(
newPw
);
Events
.
raise
(
new
PasswordChangedEvent
(
id
.
getId
(),
newPw
));
}
public
boolean
isBlocked
()
{
return
blocked
;
}
public
EmailSet
getEmails
()
{
return
emails
;
}
}
src/main/java/com/myshop/member/command/domain/MemberBlockedEvent.java
0 → 100644
View file @
969fb9e8
package
com.myshop.member.command.domain
;
import
com.myshop.common.event.Event
;
public
class
MemberBlockedEvent
extends
Event
{
private
String
memberId
;
public
MemberBlockedEvent
(
String
memberId
)
{
this
.
memberId
=
memberId
;
}
public
String
getMemberId
()
{
return
memberId
;
}
}
src/main/java/com/myshop/member/command/domain/MemberId.java
0 → 100644
View file @
969fb9e8
package
com.myshop.member.command.domain
;
import
javax.persistence.Column
;
import
javax.persistence.Embeddable
;
import
java.io.Serializable
;
import
java.util.Objects
;
@Embeddable
public
class
MemberId
implements
Serializable
{
@Column
(
name
=
"member_id"
)
private
String
id
;
protected
MemberId
()
{
}
public
MemberId
(
String
id
)
{
this
.
id
=
id
;
}
public
String
getId
()
{
return
id
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
return
true
;
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
return
false
;
MemberId
memberId
=
(
MemberId
)
o
;
return
Objects
.
equals
(
id
,
memberId
.
id
);
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
id
);
}
public
static
MemberId
of
(
String
id
)
{
return
new
MemberId
(
id
);
}
}
src/main/java/com/myshop/member/command/domain/MemberRepository.java
0 → 100644
View file @
969fb9e8
package
com.myshop.member.command.domain
;
import
org.springframework.data.jpa.repository.Lock
;
import
org.springframework.data.jpa.repository.Query
;
import
org.springframework.data.jpa.repository.QueryHints
;
import
org.springframework.data.repository.Repository
;
import
org.springframework.data.repository.query.Param
;
import
javax.persistence.LockModeType
;
import
javax.persistence.QueryHint
;
import
java.util.Optional
;
public
interface
MemberRepository
extends
Repository
<
Member
,
MemberId
>
{
Optional
<
Member
>
findById
(
MemberId
memberId
);
@Lock
(
LockModeType
.
PESSIMISTIC_WRITE
)
@QueryHints
({
@QueryHint
(
name
=
"javax.persistence.lock.timeout"
,
value
=
"3000"
)
})
@Query
(
"select m from Member m where m.id = :id"
)
Optional
<
Member
>
findByIdForUpdate
(
@Param
(
"id"
)
MemberId
memberId
);
void
save
(
Member
member
);
}
src/main/java/com/myshop/member/command/domain/MemberUnblockedEvent.java
0 → 100644
View file @
969fb9e8
package
com.myshop.member.command.domain
;
public
class
MemberUnblockedEvent
{
private
String
memberId
;
public
MemberUnblockedEvent
(
String
memberId
)
{
this
.
memberId
=
memberId
;
}
public
String
getMemberId
()
{
return
memberId
;
}
}
src/main/java/com/myshop/member/command/domain/Password.java
0 → 100644
View file @
969fb9e8
package
com.myshop.member.command.domain
;
import
javax.persistence.Column
;
import
javax.persistence.Embeddable
;
@Embeddable
public
class
Password
{
@Column
(
name
=
"password"
)
private
String
value
;
protected
Password
()
{
}
public
Password
(
String
value
)
{
this
.
value
=
value
;
}
public
boolean
match
(
String
password
)
{
return
this
.
value
.
equals
(
password
);
}
}
Prev
1
2
3
4
5
6
7
8
…
10
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment