# statische Methode und der EntityManager



## FINF_AW_Alex (25. Feb 2015)

Guten Morgen liebe Javafreunde !!

Ich hab da ein kleines Problem, ich habe eine statische Methode "isAllowed()" welche überprüfen soll ob die methode sie sie aufruft vom derzeitig eingeloggten Benutzer ausgeführt werden darf.

Benutzernamen, Gruppe u.s.w habe ich alles aber das problem ist das ich zum abgleichen eine query absenden muss und der EntityManager im statischen Kontext nicht ausführbar ist.

Deshalb habe ich eine nicht statische Methode "sql()" geschrieben die mir ein boolean liefert wenn ein Eintrag gefunden wurde.

Jetzt ist ja aber das Problem das ich in meiner statischen Methode die nichtstatische nicht aufrufen kann. :-(

Ich habe nachgelesen und gelesen das ich ein neues Objekt der nicht statischen Methode erstellen müsste aber das hieße ja das ich eine neue Klasse für die SQL_Abfrage schreiben müsste und dann komm ich wieder nicht an die Felder meiner KLasse mit der statischen Methode ran (benutzer, gruppe, rolle), oder?


ich bin verzweifelt... ich hab nur noch eine Woche um meine Projekt abzuschliessen und jetzt sowas 

weiss jemand rat? hier mal der Code meiner Klasse, es wäre cool wen jemand einen Tip hätte wie ich es lösen kann ohne ein neues Objekt erstellen zu müssen.

Grüße Alex !!



```
package setix.security;

import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.servlet.http.HttpServletRequest;


@ManagedBean
public class SecureControler {
    
    private String  user;
    
    private static  String methodenName;
    
    private boolean adminRole;
    private boolean customerRole;
    private boolean employeeRole;
    
    //Testquery liefert 2 Einträge zurück(3,6)
    private static final String sqlQuery =  "SELECT id from acl where methodenname = 'createLieferschein' and benutzername = 'alex'"+
                                                                  "or methodenname = 'createLieferschein' and gruppenname ='admin'";
    
    @PersistenceContext
    EntityManager em;
    
    //Testet die Funktion der isAllowed Methode
    public void test(){       
       isAllowed();
    }

    public static boolean isAllowed(){
        
     //aktuelle Methode abfragen welche diese Methode aufruft
        StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
        methodenName = stackTraceElement.getMethodName();
        
      if (sql() == true)
          return true;
      else return false;     
    }
    
    //Setzt die query ab und gibt true zurück wenn ein eintrag gefunden wurde
    public boolean sql(){
    
        Query query = em.createNativeQuery(sqlQuery);
    
       if (query.getResultList().isEmpty()){
             return false;
       }else
            { 
             return true;    
            }
    }
    
    
    //GETTER für Benutzerinformatinen
    public String getUser() {       
        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();      
        user        = request.getRemoteUser();
        return user;
    }

    //Getter um den aktuellen Benutzerstatus zu prüfen(admin)
    public boolean isAdminRole() {     
        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();
        adminRole = request.isUserInRole("admin");       
        return adminRole;
    }
    
    //Getter um den aktuellen Benutzerstatus zu prüfen(kunde)
    public boolean isCustomerRole() {     
        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();
        customerRole = request.isUserInRole("customer");       
        return customerRole;
    }
    
    //Getter um den aktuellen Benutzerstatus zu prüfen(mitarbeiter)
    public boolean isEmployeeRole() {     
        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();
        employeeRole = request.isUserInRole("employee");       
        return employeeRole;
    }
    
    
    //Methoden für die visuelle Darstellung der aktuellen Rechte
    //Admin
    public String adminLight(){
        adminRole = isAdminRole();
    if (adminRole == true)
        return"green";
    else return"red"; 
    }
    //Kunde
    public String customerLight(){
        customerRole = isCustomerRole();
    if (customerRole == true)
        return"green";
    else return"red"; 
    }
    //Mitarbeiter
    public String employeeLight(){
        employeeRole = isEmployeeRole();
    if (employeeRole == true)
        return"green";
    else return"red"; 
    }    
}
```


----------



## da32079 (25. Feb 2015)

Du weist schon, was Static bedeuted, oder?
Static bedeuted, dass du das damit versehene Datenfeld, oder die Methode verwenden kannst, ohne ein Objekt der Klasse zu erzeugen. Du rufst direkt an der Klasse die Methode auf: 
Klasse.Methode()

Zu deinem Problem :
Entweder du erzeugst ein Objekt von der Klasse, an dem du die Methode sql() aufrufen möchtest, oder du deklarierst die Methode sql auch als Static, oder du schreibst den Code der sql()-Methode in die Methode isAllowes()

Und wenn du eine eigene Klasse schreiben würdest, kannst du die benötigten Elemente doch auch als Parameter geben


----------



## FINF_AW_Alex (25. Feb 2015)

Hallo da32079



> oder du deklarierst die Methode sql auch als Static



 - der EntityManager kann wie ich schon geschrieben habe nicht im statischen Kontext verwendet werden das habe ich   schon versucht somit wäre variante 3 auch nicht möglich.

Am anfang wollte ich ja alles in der "isAllowed" Methode abhandeln, das geht ja aber wegen dem EM nicht.


---| EDIT |---

Hier hab ich kurz ein neues Projekt erstellt und zwei Klassen verwendet.... aber das Problem ist ja das selbe, ich kann nicht auf die SQLKlasse zugreifen weil die sqlMethode nicht statisch ist und um es nochmal zu erwähnen ich kann den EntityManager nicht in einer statischen Methode verwenden.... :-(



 


::EDIT2 (die Methode "isAllowed" empfängt nichts)


----------



## da32079 (25. Feb 2015)

Mach mal in der sql Klasse die Methode auf Static


----------



## FINF_AW_Alex (25. Feb 2015)

ZUM 1000sten MAL !! 

Ich kann den EntityManager NICHT, (NICHT) in einem STATISCHEN Kontext ausführen !!!!


----------



## stg (25. Feb 2015)

Ich finde dein ganzes Vorhaben irgendwie sehr sonderbar. Willst du tatsächlich in der Datenbank hinterlegen, welcher User welchen Java-Code ausführen darf? Wieso entscheidest du nicht einfach in der View, ob ein entsprechender CommandButton o.Ä. überhaupt gerendert wird?

Aber mal davon abgesehen: Wieso soll die besagte Methode denn überhaupt statisch sein?

Übrigens: Business-Logik in getter-Methoden ist immer noch böse. Das Thema hatten wir zwei glaube ich schon mal


----------



## FINF_AW_Alex (25. Feb 2015)

hey stg 

die Rechte werden in der Datenbank hinterlegt weil mein Chef das so will und er die Idee verfolgt das er wenn eine neue Methode der WebApplication zugefügt wird dann nur die isAllowed Methode davorhängen will.

Deshalb muss die isAllowed Methode auch statisch sein, sie muss aus jedem Package heraus erreichbar sein.


Ich habe jetzt glaube ich sowas wie eine richtige vorgehensweise gefunden:



Das Programm gibt mir ein Juhu aus wenn ich in der view die testMethod() auf einen Button lege 

aber ich glaube es wird immer noch probleme geben weil ich ja um eine ordentliche SQLQuery abschicken zu können auf  Felder der ControllerClass zugreifen mus, aus der SqlClass heraus....


----------



## stg (25. Feb 2015)

Noch eine Zwischenfrage: Ist es so gewollt, dass du wild zwischen EJB, ManagedBeans und CDI hin- und herspringst? 

Wie auch immer, deine Schlussfolgerung 





> Deshalb muss die isAllowed Methode auch statisch sein, sie muss aus jedem Package heraus erreichbar sein.


 ist falsch. Es hindert dich niemand daran eine konkrete Instanz für genau den gleichen Zweck zu nutzen. Etwa einen Stateless EJB-Service, den du injizierst. Für EJB gibt es zusätzlich auch noch die @RolesAllowed Annotation, vielleicht ist die interessant für dich. Ich hab allerdings immer noch nicht so genau verstanden, wie das Sicherheitskonzept eigentlich aussehen soll. Vermutlich weiß dein Chef das selbst nicht so recht...
Wie auch immer, mir gefällt das ganze Gehampel nicht. So ein Sicherheitskonzept sollte transparent für den Rest der Anwendung laufen. Sonst rennst du da früher oder später in ein endloses Gefrickel.


----------



## FINF_AW_Alex (25. Feb 2015)

Ja, das mit dem Gefrickel hab ich ja schon 

die @RolesAllowed Annotation kenne ich schon, aber die müsste man dann ja in jede Methode schreiben....

mein Chef ist faul und will nur das in jeder Methode vor der ausführung in der isAllowed nachgefragt wird ob der benutzer für diese Methode hinterlegt ist. So kann er auch ohne umstände neue Rechte in der Datenbank verwalten.


Ach so, und das ich zwischen Managed u.s.w hin und her springe hat den gleichen Grund weshalb ich hier auch so viele Fragen stelle und so einen wirrwar hab.... Ich programmiere erst seit 6Monaten, hab niemanden der mir sag wie ich es richtig mache und muss alles mit dem try & error Prinzip herausfinden. Ich bin bei vielem einfach nur froh wenn es funktioniert, solangsam, sehr langsam steige ich aber auch so hinter das eine oder andere Konzept ^^

....es wird......


----------



## FINF_AW_Alex (25. Feb 2015)

@stg

Okay, mal eine Frage zum erstellen einer KLasse

Du sagst ich soll die logik aus den gettern (und settern?) halten.

Ich würde jetzt gerne eine neue KLasse erstellen die mehrere String Felder hat.

  - String methodenname, benutzername, gruppenname; 

 Der gewünschte Konstruktor verlangt alle drei Felder.

 um an die Felder zu kommen muss ich dieverse methoden ausführen, wo verweise ich auf die Methoden?

 Für jedes Feld muss ich mir nämlich die Infos aus dem Request ziehen.....

 grüße Alex


----------



## FINF_AW_Alex (25. Feb 2015)

Huhu nochmal, also ich hab mir jetzt eine KLasse "TestObject" gebastelt mit der meine statische Methode arbeiten kann.

Ich habe in der statischen "isAllowed" Methode ein neues Objekt erstellt und konnte mir Benutzernamen und aufgerufene Methode ausgeben lassen.  **PRIMA**

jetzt fehlt mir nur noch der Abgleich mit der SQLDatenbank und da hab ich ein kleines Problem:

ich würde meiner Klasse "TEstObject" gerne eine Methode geben mit der ich die eingefangenen Daten dann mit der DB abgleichen kann aber ich bekomme immer eine NullPointerException.

Was habe ich in der "sqlTest" Methode falsch gemacht?

Klasse SecureController:

```
.
.
.
    //Testet die Funktion der isAllowed Methode
    public void test(){       
       isAllowed();
    }

    public static void isAllowed(){
        
        TestObject t1 = new TestObject();
        
        if (t1.sqlTest()==true)
            System.out.println("yay");
        else System.out.println("nay");
        
        System.out.println(t1.getMethodenname());
    }
.
.
.
```

Klasse TestObject:

```
.
.
.
public class TestObject {
    
    @PersistenceContext
    EntityManager em;
    
    //Klassenvariablen
    private String benutzername,methodenname,rollenname;

    //Konstruktor
    public TestObject() {
        
        StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[3];
        methodenname = stackTraceElement.getMethodName();       
        this.methodenname = methodenname;
        
        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();
        benutzername = request.getRemoteUser();    
        this.benutzername = benutzername;
        
        //hier kommt die Rollenabfrage rein
        this.rollenname = "admin";
    }
    
    //Methoden
    public boolean sqlTest(){
                
       Query query = em.createNativeQuery("SELECT id from acl where methodenname "+
                                          "='"+this.methodenname+"' and benutzername = '"+this.benutzername+"'"+
                                          "or methodenname = '"+this.methodenname+"' and gruppenname "+
                                          "='"+this.rollenname+"'");
    
       if (query.getResultList().isEmpty())
       return false;
       else return true;
    }
    
    //GETTER & SETTER
    public String getBenutzername() {
        return benutzername;
    }

    public void setBenutzername(String benutzername) {
        this.benutzername = benutzername;
    }

    public String getMethodenname() {
        return methodenname;
    }

    public void setMethodenname(String methodenname) {
        this.methodenname = methodenname;
    }

    public String getRollenname() {
        return rollenname;
    }

    public void setRollenname(String rollenname) {
        this.rollenname = rollenname;
    }   
} 
.
.
.
```


----------



## ARadauer (2. Mai 2015)

Ich muss dir leider sagen, dass du an gewissen punkten einen komplett falscjen ansatz hast. Dir fehlen da ein paar j2ee Grundlagen. .. das schafft man mit try and error nicht.  Kauf dir ein j2ee grundlagenbuch  dann wird dir einiges klar werden... empfehlen kann ich keins, ich mach nur spring...


----------



## stg (2. Mai 2015)

FINF_AW_Alex hat gesagt.:


> Was habe ich in der "sqlTest" Methode falsch gemacht?



Um dir eine kurze Beschreibung (keine vollständige Erklärung, das sprengt ein wenig den Rahmen gerade..) zu liefern:
Du erstellst in deinem Code selbst (!) eine Instanz von der Klasse TestObjekt. Die Dependency Injection des Persistence Context greift daher nicht. Deswegen ist der EntityManager immer noch <null>, wenn du darauf zugreifen willst.


----------



## KSG9|sebastian (7. Mai 2015)

Für sowas verwendet man doch bitte Spring Security. Das hat auch nix mit faul o.ä. zu tun. Warum willst du auch bitte jede Methode sichern, das ist doch völliger Quark.
Wenn du unbedingt meinst es selbst bauen zu müssen dann verwendet dafür wenigsten einen MethodInterceptor. Den kannst du vernünftig über Spring/CDI bootstrapen und auch den PersistenceContext injecten lassen.
Aber nochmal: Lass so ein Gefrickel gleich wieder sein...

Warum?
1. das Rad muss man nicht ständig neu erfinden
2. Deine Lösung ist komplett unflexibel
3. Du wirst vermutlich einen Haufen Code duplizieren weil dieser von der Stelle A aufgerufen werden darf aber von Stelle B nicht. Da du in der eigentlichen Methode aber nicht mehr unterscheiden kannst woher du kommst heißt es copy/paste
4. Weil es einfach Murks ist...


----------

