Reputation: 3964
I have a method create(Environment env)
in Java 8, which have multiple statements. Now I need to rewrite method to add support of new migration
functionality.
To add support of migration
just means:
If
Environment env
object has fieldmigration
set totrue
don't execute some code increate
function.
That's why I wrap these code blocks:
protected Environment create(Environment env)
{
statements;
if (!env.isForMigrate()) {
// executed only if it's NOT a migration
statements;
// for example: imh.create(ve)
// or: newEnv.setAps(env.getAps());
}
...
statements;
if (!env.isForMigrate()) {
// executed only if it's NOT a migration
statements;
}
...
and so on...
}
These code blocks I widespread all over create
function.
Thus I have to add conditional execution for multiple code blocks.
Can I get some advantages in case of using lambda expressions for this? Is there any pattern in Java 8?
My intention is to write something like this:
final Predicate<T> forMigrate = (func) -> {
// closure for Environment env
if (env.isForMigrate()) {
func(); // execute passed statements
}
}
...
forMigrate({
Environment newEnv = apsh().envh().im2aps(ve);
newEnv.setAps(env.getAps());
newEnv.setOsId(env.getOsId());
});
Thus I want to get lambda expression, to which I could pass any block of code. And lambda expression will execute these statements only if it's not a migration
.
forMigrate
lambda function?if (...) {}
statements in this example?Note:
Environment
class, it's auto-generated from XML file.forMigration
- only inside create
(don't make it visible anywhere) - that's why I want to assign lambda expression to variable: final ... forMigrate = (...) -> { ... }
.Environment
, dont' pass it directly to lambda. Use it from where lambda is defined.Original function create
:
protected Environment create(Environment env)
{
if(env.getHostname()!=null && env.getHostname().endsWith(".")){
String normalizedHostname = env.getHostname().substring(0, env.getHostname().length() - 1);
env.setHostname(normalizedHostname);
}
Ve ve = apsh().envh().aps2im(env);
if (ve.getHostname() == null) {
ve.setHostname(ve.getName());
}
List<String> apps = env.getApps();
Boolean passwordSet = false;
imh.create(ve);
ve = imh.getVe(ve.getCustomerId().intValue(), ve.getName());
if(env.getPassword()!= null && !env.getPassword().isEmpty()){
try{
imh.setVePassword(ve.getCustomerId(), ve.getName(), env.getPassword());
passwordSet = true;
} catch(Exception ex){
logger.error("Failed to set password for VE: " + env.getName(), ex);
}
}
if (!apps.isEmpty()) {
try {
imh.setVeApps(ve.getCustomerId().intValue(), ve.getName(), apps);
} catch (Exception ex) {
logger.error("Failed to install applications VE: {}", ex);
}
}
VeFacade vef = vehFactory.create(ve.getCustomerId(), ve.getName());
vef.operation("start");
ve = imh.getVe(ve.getCustomerId().intValue(), ve.getName());
Environment newEnv = apsh().envh().im2aps(ve);
newEnv.setAps(env.getAps());
newEnv.setOsId(env.getOsId());
newEnv.setSample(env.getSample());
newEnv.setHosting(env.getHosting());
newEnv.setDomain(env.getDomain());
newEnv.getStatus().setUptime(Long.valueOf(new Date().getTime()));
newEnv.setPassword(null); //prevent password from being saved in DB
newEnv.setPasswordSet(passwordSet);
apsh().envh().fillOsData(newEnv, apsh().teh().getOs(newEnv.getOsId()));
apsh().envh().synchPublicAddresses(newEnv, ve);
apsh().dnsh().synchDomainRecords(newEnv);
logger.info("Environment '{}' successfully created", newEnv.getName());
return newEnv;
}
How I would rewrite it in old Java 7 style:
protected Environment create(Environment env)
{
if(env.getHostname()!=null && env.getHostname().endsWith(".")){
String normalizedHostname = env.getHostname().substring(0, env.getHostname().length() - 1);
env.setHostname(normalizedHostname);
}
Ve ve = apsh().envh().aps2im(env);
if (ve.getHostname() == null) {
ve.setHostname(ve.getName());
}
List<String> apps = env.getApps();
Boolean passwordSet = false;
// NOTE: Wrap block of code
if (env.isForMigrate() == false) {
imh.create(ve);
}
ve = imh.getVe(ve.getCustomerId().intValue(), ve.getName());
if(env.getPassword()!= null && !env.getPassword().isEmpty()){
try{
imh.setVePassword(ve.getCustomerId(), ve.getName(), env.getPassword());
passwordSet = true;
} catch(Exception ex){
logger.error("Failed to set password for VE: " + env.getName(), ex);
}
}
if (!apps.isEmpty()) {
try {
imh.setVeApps(ve.getCustomerId().intValue(), ve.getName(), apps);
} catch (Exception ex) {
logger.error("Failed to install applications VE: {}", ex);
}
}
// NOTE: Wrap block of code
if (env.isForMigrate() == false) {
VeFacade vef = vehFactory.create(ve.getCustomerId(), ve.getName());
vef.operation("start");
}
ve = imh.getVe(ve.getCustomerId().intValue(), ve.getName());
Environment newEnv = apsh().envh().im2aps(ve);
// NOTE: Wrap block of code
if (env.isForMigrate() == false) {
newEnv.setAps(env.getAps());
newEnv.setOsId(env.getOsId());
newEnv.setSample(env.getSample());
}
newEnv.setHosting(env.getHosting());
newEnv.setDomain(env.getDomain());
newEnv.getStatus().setUptime(Long.valueOf(new Date().getTime()));
newEnv.setPassword(null); //prevent password from being saved in DB
newEnv.setPasswordSet(passwordSet);
apsh().envh().fillOsData(newEnv, apsh().teh().getOs(newEnv.getOsId()));
apsh().envh().synchPublicAddresses(newEnv, ve);
apsh().dnsh().synchDomainRecords(newEnv);
logger.info("Environment '{}' successfully created", newEnv.getName());
return newEnv;
}
Upvotes: 2
Views: 6004
Reputation: 2619
I don't know if this is an option for you, but in create
you could write:
Consumer<Runnable> forMigration = runnable -> {
if (environment.isForMigrate()) runnable.run();
};
and then call it like this:
forMigration.accept(() -> System.out.println("migrating"));
You will not easily get rid of that functional interface method call, though, because you can only use function call syntax (with parentheses) on functions, which cannot capture the call site's environment.
Upvotes: 0
Reputation: 4015
this is a sample based on your code
private static class Environment {
private String aps;
private String osId;
private String sample;
private boolean forMigrate;
public String getAps() {
return aps;
}
public void setAps(String aps) {
this.aps = aps;
}
public String getOsId() {
return osId;
}
public void setOsId(String osId) {
this.osId = osId;
}
public String getSample() {
return sample;
}
public void setSample(String sample) {
this.sample = sample;
}
private void forMigration(Environment e, Consumer<Environment> con) {
if (!e.isForMigrate()) {
con.accept(e);
}
}
public boolean isForMigrate() {
return forMigrate;
}
public void setForMigrate(boolean isForMigrate) {
this.forMigrate = isForMigrate;
}
protected Environment create(Environment env) {
Environment newEnv= new Environment();
List<String> imh=new ArrayList<>();
forMigration(env, e -> {newEnv.setAps(e.getAps());newEnv.setOsId(e.getOsId()); });
forMigration(env, e -> {imh.add("test for generic call"); });
return newEnv;
}
}
Using a Consumer you can reference the same Enviroment you use for the check in the lambda (if a Enviroment is needed).
Upvotes: 3
Reputation: 328659
You could write something like:
private static void forMigrate(Environnement env, Runnable r) {
if (!env.isForMigrate()) r.run();
}
And in your code:
forMigrate(env, () -> {
newEnv.setAps(env.getAps());
newEnv.setOsId(env.getOsId());
newEnv.setSample(env.getSample());
}
);
Upvotes: 2