Spring JPA

I am tryna Delete the forgotPassword Enetity if the Otp expired time is passed out and that is 10 sec right now but after the Otp time expired the otp entity is not deleting itself from Db . Here is the implemet
if (forgotPassword.getOtpExpireDate().before(Date.from(Instant.now()))) {

if (forgotPassword.getOtpExpireDate().before(Date.from(Instant.now()))) {

Long fId = forgotPassword.getForgotpasswordId();
System.out.println("The Password id is "+ fId);

emailService.deleteForgotPasswordById(fId);
logger.warn("The Time is expired", forgotPassword.getOtpExpireDate());
throw new OtpNotFoundExcpetion("Otp Expired");
}
}
if (forgotPassword.getOtpExpireDate().before(Date.from(Instant.now()))) {

if (forgotPassword.getOtpExpireDate().before(Date.from(Instant.now()))) {

Long fId = forgotPassword.getForgotpasswordId();
System.out.println("The Password id is "+ fId);

emailService.deleteForgotPasswordById(fId);
logger.warn("The Time is expired", forgotPassword.getOtpExpireDate());
throw new OtpNotFoundExcpetion("Otp Expired");
}
}
Can anyone help
82 Replies
JavaBot
JavaBot5mo ago
This post has been reserved for your question.
Hey @Danix! Please use /close or the Close Post button above when your problem is solved. Please remember to follow the help guidelines. This post will be automatically closed after 300 minutes of inactivity.
TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.
Danix
DanixOP5mo ago
@dan1st | Daniel can u see it
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
JavaBot
JavaBot5mo ago
💤 Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived. If your question was not answered yet, feel free to re-open this post or create a new one. In case your post is not getting any attention, you can try to use /help ping. Warning: abusing this will result in moderative actions taken against you.
Danix
DanixOP5mo ago
I changed it but facing the same thing again ! i cant find any delete call here
Hibernate: select fp1_0.fp_id,fp1_0.otp,fp1_0.otp_expire_date,fp1_0.user_email from forgot_password fp1_0 where fp1_0.otp=? and fp1_0.user_email=?
Hibernate: select u1_0.email,fp1_0.fp_id,fp1_0.otp,fp1_0.otp_expire_date,fp1_0.user_email,u1_0.name,u1_0.password from registered_user u1_0 left join forgot_password fp1_0 on u1_0.email=fp1_0.user_email where u1_0.email=?
The Password id is 1
2024-07-15T09:15:16.276+05:30  WARN 8260 --- [nio-8080-exec-8] c.S.S.c.ForgotPasswordController  : The Time is expired
2024-07-15T09:15:16.276+05:30 ERROR 8260 --- [nio-8080-exec-8] c.S.S.c.ForgotPasswordController  : The error occured
Hibernate: select fp1_0.fp_id,fp1_0.otp,fp1_0.otp_expire_date,fp1_0.user_email from forgot_password fp1_0 where fp1_0.otp=? and fp1_0.user_email=?
Hibernate: select u1_0.email,fp1_0.fp_id,fp1_0.otp,fp1_0.otp_expire_date,fp1_0.user_email,u1_0.name,u1_0.password from registered_user u1_0 left join forgot_password fp1_0 on u1_0.email=fp1_0.user_email where u1_0.email=?
The Password id is 1
2024-07-15T09:15:16.276+05:30  WARN 8260 --- [nio-8080-exec-8] c.S.S.c.ForgotPasswordController  : The Time is expired
2024-07-15T09:15:16.276+05:30 ERROR 8260 --- [nio-8080-exec-8] c.S.S.c.ForgotPasswordController  : The error occured
@AJediMasterIam
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
Danix
DanixOP5mo ago
this
@Transactional
public void deleteForgotPasswordById(Long id) {
forgotPasswordRepository.deleteById(id);
}
@Transactional
public void deleteForgotPasswordById(Long id) {
forgotPasswordRepository.deleteById(id);
}
i will delete the forgot password entity from db after expiration
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
Danix
DanixOP5mo ago
@Transactional
public void deleteForgotPasswordById(Long id) {
log.info("Deleting ForgotPassword entity with id: " + id);
forgotPasswordRepository.deleteById(id);
log.info("Deleted ForgotPassword entity with id: " + id);
}
@Transactional
public void deleteForgotPasswordById(Long id) {
log.info("Deleting ForgotPassword entity with id: " + id);
forgotPasswordRepository.deleteById(id);
log.info("Deleted ForgotPassword entity with id: " + id);
}
i did it and getting the print like Deleting ForgotPassword entity with id: 1 and Deleted ForgotPassword entity with id: 1 but not deleted the data from DB
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
Danix
DanixOP5mo ago
Where ?
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
Danix
DanixOP5mo ago
i think i did the same think ? This is the sql
Hibernate: select fp1_0.fp_id,fp1_0.otp,fp1_0.otp_expire_date,fp1_0.user_email from forgot_password fp1_0 where fp1_0.otp=? and fp1_0.user_email=?
Hibernate: select u1_0.email,fp1_0.fp_id,fp1_0.otp,fp1_0.otp_expire_date,fp1_0.user_email,u1_0.name,u1_0.password from registered_user u1_0 left join forgot_password fp1_0 on u1_0.email=fp1_0.user_email where u1_0.email=?
The Password id is 1
Hibernate: select fp1_0.fp_id,fp1_0.otp,fp1_0.otp_expire_date,fp1_0.user_email from forgot_password fp1_0 where fp1_0.otp=? and fp1_0.user_email=?
Hibernate: select u1_0.email,fp1_0.fp_id,fp1_0.otp,fp1_0.otp_expire_date,fp1_0.user_email,u1_0.name,u1_0.password from registered_user u1_0 left join forgot_password fp1_0 on u1_0.email=fp1_0.user_email where u1_0.email=?
The Password id is 1
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
Danix
DanixOP5mo ago
yehh but whats the issue i am getting bcz the query is right i think so where the issue should be ?
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
Danix
DanixOP5mo ago
when i was making the forgot password table in the Db then i made it cascade delete My Forgot Password Table says
Related Tables:
Target registered_user (user_email → email)
On Update RESTRICT
On Delete RESTRICT
Related Tables:
Target registered_user (user_email → email)
On Update RESTRICT
On Delete RESTRICT
@dan1st | Daniel can u see the issue is not removing
dan1st
dan1st5mo ago
What does forgetPasswordRepository.deleteById return? it sais an error occured. Where? Is there a stack trace? Are you printing that?
Danix
DanixOP5mo ago
nothing just void yeh i am printing it
dan1st
dan1st5mo ago
Can you show that part?
Danix
DanixOP5mo ago
if (forgotPassword == null) {
logger.warn("ForgotPassword not found for OTP {} and email {}", otp, user.getEmail());
model.addAttribute("error", "OTP not found");
return "otpchecker";
}


if (forgotPassword.getOtpExpireDate().before(Date.from(Instant.now()))) {

Long fId = forgotPassword.getForgotpasswordId();
System.out.println("The Password id is "+ fId);

emailService.deleteForgotPasswordById(fId);
logger.warn("The Time is expired", forgotPassword.getOtpExpireDate());
throw new OtpNotFoundExcpetion("Otp Expired");
}
if (forgotPassword == null) {
logger.warn("ForgotPassword not found for OTP {} and email {}", otp, user.getEmail());
model.addAttribute("error", "OTP not found");
return "otpchecker";
}


if (forgotPassword.getOtpExpireDate().before(Date.from(Instant.now()))) {

Long fId = forgotPassword.getForgotpasswordId();
System.out.println("The Password id is "+ fId);

emailService.deleteForgotPasswordById(fId);
logger.warn("The Time is expired", forgotPassword.getOtpExpireDate());
throw new OtpNotFoundExcpetion("Otp Expired");
}
After printing the The Time is Expired the error is thrown i think stack is from there
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
Danix
DanixOP5mo ago
The Repo class
package com.ShelfSpace.ShelfSpace.repository;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import com.ShelfSpace.ShelfSpace.entites.ForgotPassword;
import com.ShelfSpace.ShelfSpace.entites.User;

public interface ForgotPasswordRepository extends JpaRepository<ForgotPassword, Long> {

@Query("SELECT fp FROM ForgotPassword fp WHERE fp.otp = :otp AND fp.user = :user")
Optional<ForgotPassword> findByOtpAndUser(int otp, User user);


}
package com.ShelfSpace.ShelfSpace.repository;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import com.ShelfSpace.ShelfSpace.entites.ForgotPassword;
import com.ShelfSpace.ShelfSpace.entites.User;

public interface ForgotPasswordRepository extends JpaRepository<ForgotPassword, Long> {

@Query("SELECT fp FROM ForgotPassword fp WHERE fp.otp = :otp AND fp.user = :user")
Optional<ForgotPassword> findByOtpAndUser(int otp, User user);


}
The Service class method
@Transactional
public void deleteForgotPasswordById(Long id) {
log.info("Deleting ForgotPassword entity with id: " + id);
forgotPasswordRepository.deleteById(id);
log.info("Deleted ForgotPassword entity with id: " + id);
}
@Transactional
public void deleteForgotPasswordById(Long id) {
log.info("Deleting ForgotPassword entity with id: " + id);
forgotPasswordRepository.deleteById(id);
log.info("Deleted ForgotPassword entity with id: " + id);
}
Here it is been used

if (forgotPassword == null) {
logger.warn("ForgotPassword not found for OTP {} and email {}", otp, user.getEmail());
model.addAttribute("error", "OTP not found");
return "otpchecker";
}


if (forgotPassword.getOtpExpireDate().before(Date.from(Instant.now()))) {

Long fId = forgotPassword.getForgotpasswordId();
System.out.println("The Password id is "+ fId);

emailService.deleteForgotPasswordById(fId);
logger.warn("The Time is expired", forgotPassword.getOtpExpireDate());
throw new OtpNotFoundExcpetion("Otp Expired");
}

System.out.println("the Otp is Correct " +otp);
logger.warn("The user is founded", user);
session.invalidate();
return"newpassword";


}
catch (OtpNotFoundExcpetion e) {
logger.error("The error occured", e);
model.addAttribute("error", "Otp is Invalid");
return "otpchecker";
}
catch (Exception e) {
logger.error("The error occured", e);
model.addAttribute("error", "Otp is Invalid");
return "otpchecker";
}
}

if (forgotPassword == null) {
logger.warn("ForgotPassword not found for OTP {} and email {}", otp, user.getEmail());
model.addAttribute("error", "OTP not found");
return "otpchecker";
}


if (forgotPassword.getOtpExpireDate().before(Date.from(Instant.now()))) {

Long fId = forgotPassword.getForgotpasswordId();
System.out.println("The Password id is "+ fId);

emailService.deleteForgotPasswordById(fId);
logger.warn("The Time is expired", forgotPassword.getOtpExpireDate());
throw new OtpNotFoundExcpetion("Otp Expired");
}

System.out.println("the Otp is Correct " +otp);
logger.warn("The user is founded", user);
session.invalidate();
return"newpassword";


}
catch (OtpNotFoundExcpetion e) {
logger.error("The error occured", e);
model.addAttribute("error", "Otp is Invalid");
return "otpchecker";
}
catch (Exception e) {
logger.error("The error occured", e);
model.addAttribute("error", "Otp is Invalid");
return "otpchecker";
}
}
dan1st
dan1st5mo ago
Can you show the full stack trace? you are getting some exception
Danix
DanixOP5mo ago
yehh here is the stack trace
Danix
DanixOP5mo ago
JavaBot
JavaBot5mo ago
💤 Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived. If your question was not answered yet, feel free to re-open this post or create a new one. In case your post is not getting any attention, you can try to use /help ping. Warning: abusing this will result in moderative actions taken against you.
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
dan1st
dan1st5mo ago
that ^
Danix
DanixOP5mo ago
hmm so should i have to throw an exception at that point or not ?
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
dan1st
dan1st5mo ago
it's also possible to configure it to commit the transaction on that exception I think using noRollbackFor or similar
Tomasm21
Tomasm215mo ago
The issue is due to relatioship guys. User had:
@OneToOne(mappedBy = "user" , cascade = CascadeType.ALL)
private ForgotPassword forgotPassword;
@OneToOne(mappedBy = "user" , cascade = CascadeType.ALL)
private ForgotPassword forgotPassword;
And ForgotPassword:
@OneToOne
@JoinColumn(name = "user_email" , nullable = false)
private User user;
@OneToOne
@JoinColumn(name = "user_email" , nullable = false)
private User user;
He can delete User and cascade to ForgotPassword But he can't delete ForgotPassword because of the reference. He tries, but it doesn't happen
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
Tomasm21
Tomasm215mo ago
I solved him the issue. And explained. Also learned myself. See full class:
Tomasm21
Tomasm215mo ago
Method: public String verifyOtp(@RequestParam String otp , Model model , HttpSession session) line 126
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
Tomasm21
Tomasm215mo ago
No it doesn't I already tried I had to nullify the reference by userid.setForgotPassword(null); It deletes the entity and no matter that it throws an exception
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
Tomasm21
Tomasm215mo ago
his exception
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
Tomasm21
Tomasm215mo ago
Nah he has this single transaction in that method.
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
Tomasm21
Tomasm215mo ago
Bye I believe in your statements. Usually it's true.
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
Tomasm21
Tomasm215mo ago
Then why when on this method we have @Trabsactional and we delete the reference from user, save it to database, then delete the forgetPassword entity and at the end we throw an exception then I check the databse and see that it's deleted?
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
Tomasm21
Tomasm215mo ago
Hibernate deleted it after the exception was thrown:
No description
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
dan1st
dan1st5mo ago
it depends on how that method is called though
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
Tomasm21
Tomasm215mo ago
When I removed @Transactional annotation from the method, the entity was still removed. But not after the exception, but before it.
dan1st
dan1st5mo ago
it depends on the exception. Not all exceptions are causing a rollback IIRC
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
Tomasm21
Tomasm215mo ago
yes
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
dan1st
dan1st5mo ago
e.g. I think ResponseStatusExceptions don't cause rollbacks
Tomasm21
Tomasm215mo ago
Now tell me how to turn on transaction logging. we have only these:
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.show_sql=true

logging.level.org.springframework.security=DEBUG
#logging.level.org.springframework=DEBUG
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.show_sql=true

logging.level.org.springframework.security=DEBUG
#logging.level.org.springframework=DEBUG
dan1st
dan1st5mo ago
Stack Overflow
Showing a Spring transaction in log
I configured spring with transactional support. Is there any way to log transactions just to ensure I set up everything correctly? Showing in the log is a good way to see what is happening.
Unknown User
Unknown User5mo ago
Message Not Public
Sign In & Join Server To View
dan1st
dan1st5mo ago
transactions are rolled back on unchecked exceptions (by default) cc @IncognitoBurrito @Tomasm21
Tomasm21
Tomasm215mo ago
His exception that is thrown is this:
No description
dan1st
dan1st5mo ago
which is rolled back if not stated otherwise
Tomasm21
Tomasm215mo ago
I don't know wheret it is stated otherwise.
dan1st
dan1st5mo ago
so the exception undoes the deletion which I think was initially stated by IncognitoBurrito
Tomasm21
Tomasm215mo ago
Danix was upset because he couldn't delete the entity anyhow. I read the info that in such a case we can manually nullify the reference in the parent entity and save it. Then we can delete the child entity. So the key was:
//.....
User userid = forgotPassword.getUser();
System.out.println("USER BEFORE DELETION: "+userid.toString());
// Remove the reference in the User entity
userid.setForgotPassword(null);
// Save the User entity to update the reference
User savedUser = userRepository.save(userid);

System.out.println("SAVED USER: "+savedUser.toString());
// emailService.deleteForgotPasswordById(fId);

logger.info("Deleting ForgotPassword entity with id: " + fId);
forgotPasswordRepository.deleteById(fId);
//....
//.....
User userid = forgotPassword.getUser();
System.out.println("USER BEFORE DELETION: "+userid.toString());
// Remove the reference in the User entity
userid.setForgotPassword(null);
// Save the User entity to update the reference
User savedUser = userRepository.save(userid);

System.out.println("SAVED USER: "+savedUser.toString());
// emailService.deleteForgotPasswordById(fId);

logger.info("Deleting ForgotPassword entity with id: " + fId);
forgotPasswordRepository.deleteById(fId);
//....
But now from experienced users I hear that it's nonsense and due to thrown exception the deletion cannot happen. The rollback should occur. If you are in the mood to investigate it and to prove that something special happened then you can invite me.
dan1st
dan1st5mo ago
such a rollback literally ensures the entity not being deleted and according in the stack trace, I don't see anything about the cascading issue as of when the OP posted the stack trace
Tomasm21
Tomasm215mo ago
I have made Spring Console output. Currently deleting ugly looking symbols and soon will log you here. It's when transaction log is on. I don't know it. I learn it. Maybe you as more experienced will explain me.
Tomasm21
Tomasm215mo ago
Tomasm21
Tomasm215mo ago
The OP took my edited code. And is happy with it. Now the discussion object is that deletion cannot happen. The exception is not checked.
dan1st
dan1st5mo ago
That seems like there's no @Transactional active there
Tomasm21
Tomasm215mo ago
Perhaps. I removed the annotation:
No description
dan1st
dan1st5mo ago
Then you can't expect to reproduce what the OP is getting
Tomasm21
Tomasm215mo ago
Ok. I will put the annotation back. And show the console.
Tomasm21
Tomasm215mo ago
Tomasm21
Tomasm215mo ago
In both cases the entity was deleted. And I don't know of the rollback that should occur. Should I see it in the console output?
dan1st
dan1st5mo ago
that's because the whole thing is wrapped in a try-catch block I think but idk their code
Tomasm21
Tomasm215mo ago
I had to put in a lot of efforts to get the rollback to work: I had to show specific criteria for the rollback:
@PostMapping("/verify-otp")
@Transactional(rollbackOn = OtpNotFoundExcpetion.class)
public String verifyOtp(@RequestParam String otp , Model model , HttpSession session) {
//.....
@PostMapping("/verify-otp")
@Transactional(rollbackOn = OtpNotFoundExcpetion.class)
public String verifyOtp(@RequestParam String otp , Model model , HttpSession session) {
//.....
Then throw this unchecked exception in the try block :
//.....
forgotPasswordRepository.deleteById(fId);
throw new OtpNotFoundExcpetion("Otp Expired");
}
//....
//.....
forgotPasswordRepository.deleteById(fId);
throw new OtpNotFoundExcpetion("Otp Expired");
}
//....
and to catch it in the catch block and to re-throw it:
catch (OtpNotFoundExcpetion e) {
logger.error("The error occured", e);
model.addAttribute("error", "Otp is Invalid");
//return "otpchecker";
throw e; // Re-throw to ensure transaction rollback
}
catch (OtpNotFoundExcpetion e) {
logger.error("The error occured", e);
model.addAttribute("error", "Otp is Invalid");
//return "otpchecker";
throw e; // Re-throw to ensure transaction rollback
}
Only then my transaction was rolled back and then entity was put back and undeleted. Damn.. lol
dan1st
dan1st5mo ago
The rollbackOn = OtpNotFoundExcpetion.class wouldn't be necessary and just removing the catch(Exception) block would probably be sufficient
Tomasm21
Tomasm215mo ago
You are right. The rollback really occurs if there are no any try-catch blocks and with a single @Transactional annotation. Hibernate doesn't initiate the deletion at all. Then when we throw such unchecked exception then it rolls back. Now I will rememebr how to do it. But since our task is to show error messages in thymeleaf templates we will throw custom exceptions and will use try catch blocks. And we need to delete entity in specific circumstances. Thank you. This thread is over. To sum up everything, I see that nor @Transactional nor the throw of the exception and the rollback are not factors that prevented Danix way to delete the entity. If we don't do an exception and return a string (template) and we assign the error message model.addAttribute("error", "Otp Expired"); then the way Danix deletes his entity actually doesn't work here:
if (forgotPassword.getOtpExpireDate().before(Date.from(Instant.now()))) {

Long fId = forgotPassword.getForgotpasswordId();
System.out.println("The Password id is "+ fId);

User userid = forgotPassword.getUser();
System.out.println("USER BEFORE DELETION: "+userid.toString());

//userid.setForgotPassword(null);



logger.info("Deleting ForgotPassword entity with id: " + fId);
//forgotPasswordRepository.deleteById(fId);
emailService.deleteForgotPasswordById(fId);

User savedUser = userRepository.findByEmail(userid.getEmail()).orElse(null);

System.out.println("USER AFTER DELETION: "+savedUser.toString());

logger.warn("The Time is expired: {} and now is: {}", forgotPassword.getOtpExpireDate(), Date.from(Instant.now()).toString());
model.addAttribute("error", "Otp Expired");
return "otpchecker";
// throw new OtpNotFoundExcpetion("Otp Expired");
}
if (forgotPassword.getOtpExpireDate().before(Date.from(Instant.now()))) {

Long fId = forgotPassword.getForgotpasswordId();
System.out.println("The Password id is "+ fId);

User userid = forgotPassword.getUser();
System.out.println("USER BEFORE DELETION: "+userid.toString());

//userid.setForgotPassword(null);



logger.info("Deleting ForgotPassword entity with id: " + fId);
//forgotPasswordRepository.deleteById(fId);
emailService.deleteForgotPasswordById(fId);

User savedUser = userRepository.findByEmail(userid.getEmail()).orElse(null);

System.out.println("USER AFTER DELETION: "+savedUser.toString());

logger.warn("The Time is expired: {} and now is: {}", forgotPassword.getOtpExpireDate(), Date.from(Instant.now()).toString());
model.addAttribute("error", "Otp Expired");
return "otpchecker";
// throw new OtpNotFoundExcpetion("Otp Expired");
}
emailService.deleteForgotPasswordById(fId):
@Transactional
public void deleteForgotPasswordById(Long id) {
log.info("Deleting ForgotPassword entity with id: " + id);
forgotPasswordRepository.deleteById(id);
log.info("Deleted ForgotPassword entity with id: " + id);
}
@Transactional
public void deleteForgotPasswordById(Long id) {
log.info("Deleting ForgotPassword entity with id: " + id);
forgotPasswordRepository.deleteById(id);
log.info("Deleted ForgotPassword entity with id: " + id);
}
This doesn't make the ForgotPassword entity to be deleted.
JavaBot
JavaBot5mo ago
💤 Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived. If your question was not answered yet, feel free to re-open this post or create a new one. In case your post is not getting any attention, you can try to use /help ping. Warning: abusing this will result in moderative actions taken against you.
Want results from more Discord servers?
Add your server