<commit_before>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

package org.apache.airavata.common.registry.api.impl;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Set;

import javax.jcr.Credentials;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.RepositoryFactory;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;

import org.apache.airavata.common.registry.api.Registry;
import org.apache.airavata.common.registry.api.user.UserManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JCRRegistry extends Observable implements Registry{

    private static final String XML_PROPERTY_NAME = "XML";

    public static final String PUBLIC = "PUBLIC";

    private Repository repository;
    private Credentials credentials;
    private UserManager userManager;
    private String username;
    private URI repositoryURI;
    private Class registryRepositoryFactory;
    private Map<String,String> connectionMap;
    private String password;
    private Session defaultSession=null;
    private boolean sessionKeepAlive=false;
    private EventListener workspaceChangeEventListener;
    
	private Thread sessionManager;
    private static final int SESSION_TIME_OUT = 60000;
    private static final int DEFINITE_SESSION_TIME_OUT = 300000;
    private static Logger log = LoggerFactory.getLogger(JCRRegistry.class);
    private Map<Node,Map<String,Node>> sessionNodes;
    private Map<Node,List<Node>> sessionNodeChildren;
    private Map<Session,Integer> currentSessionUseCount=new HashMap<Session, Integer>();
    private boolean threadRun = true;
    
    public JCRRegistry(URI repositoryURI, String className, String user, String pass, Map<String, String> map)
            throws RepositoryException {
        try {
            /*
             * Load the configuration from properties file at this level and create the object
             */
            connectionMap = map;
            registryRepositoryFactory = Class.forName(className);
            Constructor c = registryRepositoryFactory.getConstructor();
            RepositoryFactory repositoryFactory = (RepositoryFactory) c.newInstance();
            setRepositoryURI(repositoryURI);
            repository = repositoryFactory.getRepository(connectionMap);
            setUsername(user);
            setPassword(<PASSWORD>);
            credentials = new SimpleCredentials(getUsername(), new String(pass).toCharArray());
            definiteSessionTimeout();
            workspaceChangeEventListener=new EventListener() {
				
				public void onEvent(EventIterator events) {
					for(;events.hasNext();){
						Event event=events.nextEvent();
						boolean isPropertyChange = (event.getType()&(Event.PROPERTY_CHANGED|Event.PROPERTY_ADDED|Event.PROPERTY_REMOVED))>0;
						try {
							String path = event.getPath();
							synchronized (sessionSynchronousObject) {
//								System.out.println("something happened: " + event.getType() + " " + path);
								List<Node> nodesToRemove=new ArrayList<Node>();
								Set<Node> nodeIterator = getSessionNodes().keySet();
								for (Node node : nodeIterator) {
									if (node == null) {
										if (path.equals("/")) {
											nodesToRemove.add(node);
										}
									} else {
										if (node.getSession().isLive()) {
											if (isPropertyChange){
												if (node.getPath().equals(path)) {
													nodesToRemove.add(node);
												}
											}else if (node.getPath().startsWith(path) || path.startsWith(node.getPath())) {
												nodesToRemove.add(node);
											}
										}
									}
								}
								for(Node node:nodesToRemove){
									getSessionNodes().remove(node);
								}
								nodeIterator = getSessionNodeChildren().keySet();
								nodesToRemove.clear();
								for (Node node : nodeIterator) {
									if (node.getSession().isLive()) {
										if (isPropertyChange){
											if (node.getPath().equals(path)) {
												nodesToRemove.add(node);
											}
										}else if (node.getPath().startsWith(path) || path.startsWith(node.getPath())) {
											nodesToRemove.add(node);
										}
									}
								}
								for(Node node:nodesToRemove){
									getSessionNodeChildren().remove(node);
								}
							}
							triggerObservers(this);
						} catch (RepositoryException e) {
							e.printStackTrace();
						}
					}
					
				}
			};
        } catch (ClassNotFoundException e) {
            log.error("Error class path settting", e);
        } catch (RepositoryException e) {
            log.error("Error connecting Remote Registry instance", e);
            throw e;
        } catch (Exception e) {
            log.error("Error init", e);
        }
    }
    
    private void definiteSessionTimeout(){
    	Thread m=new Thread(new Runnable() {
			public void run() {
				while (threadRun){
					int timeoutCount=0;
					int shortStep=10000;
					Session currentSession=defaultSession;
					while(timeoutCount<DEFINITE_SESSION_TIME_OUT){
						try {
							Thread.sleep(shortStep);
						} catch (InterruptedException e) {
							//life sucks anyway, so who cares if this exception is thrown
						}
						timeoutCount=timeoutCount+shortStep;
						if (currentSession!=defaultSession){
							//reset start from begining since its a new session
							currentSession=defaultSession;
							timeoutCount=0;
						}
					}
					reallyCloseSession(defaultSession);
				}
				
			}
		});
    	m.start();
    }
    
    private void setupSessionManagement(){
    	stopSessionManager();
        setSessionKeepAlive(true);
    	sessionManager=new Thread(new Runnable() {
			public void run() {
				while (!isSessionInvalid() && isSessionKeepAlive()){
					try {
						setSessionKeepAlive(false);
						Thread.sleep(SESSION_TIME_OUT);
					} catch (InterruptedException e) {
						//no issue
					}
				}
				reallyCloseSession(defaultSession);
			}
		});
    	sessionManager.start();
    }
    
    private void stopSessionManager(){
    	if (sessionManager!=null) {
			sessionManager.interrupt();
		}
    }
    protected boolean isSessionKeepAlive() {
		return sessionKeepAlive;
	}

	public JCRRegistry(Repository repo, Credentials credentials) {
        this.repository = repo;
        this.credentials = credentials;
    }

	protected Node getRootNode(Session session) throws RepositoryException {
		String ROOT_NODE_TEXT = "root";
		if (!getSessionNodes().containsKey(null) || !getSessionNodes().get(null).get(ROOT_NODE_TEXT).getSession().isLive()){
			getSessionNodes().put(null, new HashMap<String, Node>());
			getSessionNodes().get(null).put(ROOT_NODE_TEXT, session.getRootNode());
		}
		return getOrAddNode(null, ROOT_NODE_TEXT);
	}
	
	public Session getSession() throws RepositoryException {
    	if (isSessionInvalid()){
    		reallyCloseSession(defaultSession);
        	synchronized (sessionSynchronousObject) {
//	    		System.out.println("session created");
		        Session session = null;
		        try {
		            session = repository.login(credentials);
		            if (session == null) {
		                session = resetSession(session);
		            }
		        } catch (Exception e) {
		            session = resetSession(session);
		        }
		        defaultSession=session;
				if (defaultSession!=null) {
					defaultSession
							.getWorkspace()
							.getObservationManager()
							.addEventListener(
									getWorkspaceChangeEventListener(),
									Event.NODE_ADDED | Event.NODE_REMOVED
											| Event.NODE_MOVED | Event.PROPERTY_CHANGED | Event.PROPERTY_ADDED | Event.PROPERTY_REMOVED, "/", true,
									null, null, false);
					currentSessionUseCount.put(session, 1);
				}
        	}
	        setupSessionManagement();
    	}else{
            setSessionKeepAlive(true);
            synchronized (sessionSynchronousObject) {
		        currentSessionUseCount.put(defaultSession, currentSessionUseCount.get(defaultSession)+1);
        	}
    	}
        return defaultSession;
    }

    protected Session resetSession(Session session){
        try {
            Constructor c = registryRepositoryFactory.getConstructor();
            RepositoryFactory repositoryFactory = (RepositoryFactory) c.newInstance();
            setRepositoryURI(repositoryURI);
            repository = repositoryFactory.getRepository(connectionMap);
            setUsername(username);
            credentials = new SimpleCredentials(getUsername(), getPassword().toCharArray());
            session = repository.login(credentials);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (InstantiationException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (IllegalAccessException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (InvocationTargetException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (RepositoryException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        return session;
    }

    protected Node getOrAddNode(Node node, String name) throws RepositoryException {
    	Map<Node, Map<String, Node>> sessionNodes = getSessionNodes();
    	if (sessionNodes.containsKey(node)){
    		if (sessionNodes.get(node)!=null && sessionNodes.get(node).containsKey(name)){
    			if (sessionNodes.get(node).get(name).getSession().isLive()){
    				return sessionNodes.get(node).get(name);
    			}
    		}
    	}else{
    		sessionNodes.put(node,new HashMap<String, Node>());
    	}
        Node node1 = null;
        try {
//        	System.out.println("node extracted");
//        	if (node==null){ //root node
//        		node1=getSession().getRootNode();
//        	}else{
	            node1 = node.getNode(name);
//        	}
        	sessionNodes.get(node).put(name, node1);
        } catch (PathNotFoundException pnfe) {
            node1 = node.addNode(name);
        } catch (RepositoryException e) {
            String msg = "failed to resolve the path of the given node ";
            log.debug(msg);
            throw new RepositoryException(msg, e);
        }<commit_msg>handling the case where the root node session has expired etc.<commit_after>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

package org.apache.airavata.common.registry.api.impl;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Set;

import javax.jcr.Credentials;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.RepositoryFactory;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;

import org.apache.airavata.common.registry.api.Registry;
import org.apache.airavata.common.registry.api.user.UserManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JCRRegistry extends Observable implements Registry{

    private static final String XML_PROPERTY_NAME = "XML";

    public static final String PUBLIC = "PUBLIC";

    private Repository repository;
    private Credentials credentials;
    private UserManager userManager;
    private String username;
    private URI repositoryURI;
    private Class registryRepositoryFactory;
    private Map<String,String> connectionMap;
    private String password;
    private Session defaultSession=null;
    private boolean sessionKeepAlive=false;
    private EventListener workspaceChangeEventListener;
    
	private Thread sessionManager;
    private static final int SESSION_TIME_OUT = 60000;
    private static final int DEFINITE_SESSION_TIME_OUT = 300000;
    private static Logger log = LoggerFactory.getLogger(JCRRegistry.class);
    private Map<Node,Map<String,Node>> sessionNodes;
    private Map<Node,List<Node>> sessionNodeChildren;
    private Map<Session,Integer> currentSessionUseCount=new HashMap<Session, Integer>();
    private boolean threadRun = true;
    
    public JCRRegistry(URI repositoryURI, String className, String user, String pass, Map<String, String> map)
            throws RepositoryException {
        try {
            /*
             * Load the configuration from properties file at this level and create the object
             */
            connectionMap = map;
            registryRepositoryFactory = Class.forName(className);
            Constructor c = registryRepositoryFactory.getConstructor();
            RepositoryFactory repositoryFactory = (RepositoryFactory) c.newInstance();
            setRepositoryURI(repositoryURI);
            repository = repositoryFactory.getRepository(connectionMap);
            setUsername(user);
            setPassword(<PASSWORD>);
            credentials = new SimpleCredentials(getUsername(), new String(pass).toCharArray());
            definiteSessionTimeout();
            workspaceChangeEventListener=new EventListener() {
				
				public void onEvent(EventIterator events) {
					for(;events.hasNext();){
						Event event=events.nextEvent();
						boolean isPropertyChange = (event.getType()&(Event.PROPERTY_CHANGED|Event.PROPERTY_ADDED|Event.PROPERTY_REMOVED))>0;
						try {
							String path = event.getPath();
							synchronized (sessionSynchronousObject) {
//								System.out.println("something happened: " + event.getType() + " " + path);
								List<Node> nodesToRemove=new ArrayList<Node>();
								Set<Node> nodeIterator = getSessionNodes().keySet();
								for (Node node : nodeIterator) {
									if (node == null) {
										if (path.equals("/")) {
											nodesToRemove.add(node);
										}
									} else {
										if (node.getSession().isLive()) {
											if (isPropertyChange){
												if (node.getPath().equals(path)) {
													nodesToRemove.add(node);
												}
											}else if (node.getPath().startsWith(path) || path.startsWith(node.getPath())) {
												nodesToRemove.add(node);
											}
										}
									}
								}
								for(Node node:nodesToRemove){
									getSessionNodes().remove(node);
								}
								nodeIterator = getSessionNodeChildren().keySet();
								nodesToRemove.clear();
								for (Node node : nodeIterator) {
									if (node.getSession().isLive()) {
										if (isPropertyChange){
											if (node.getPath().equals(path)) {
												nodesToRemove.add(node);
											}
										}else if (node.getPath().startsWith(path) || path.startsWith(node.getPath())) {
											nodesToRemove.add(node);
										}
									}
								}
								for(Node node:nodesToRemove){
									getSessionNodeChildren().remove(node);
								}
							}
							triggerObservers(this);
						} catch (RepositoryException e) {
							e.printStackTrace();
						}
					}
					
				}
			};
        } catch (ClassNotFoundException e) {
            log.error("Error class path settting", e);
        } catch (RepositoryException e) {
            log.error("Error connecting Remote Registry instance", e);
            throw e;
        } catch (Exception e) {
            log.error("Error init", e);
        }
    }
    
    private void definiteSessionTimeout(){
    	Thread m=new Thread(new Runnable() {
			public void run() {
				while (threadRun){
					int timeoutCount=0;
					int shortStep=10000;
					Session currentSession=defaultSession;
					while(timeoutCount<DEFINITE_SESSION_TIME_OUT){
						try {
							Thread.sleep(shortStep);
						} catch (InterruptedException e) {
							//life sucks anyway, so who cares if this exception is thrown
						}
						timeoutCount=timeoutCount+shortStep;
						if (currentSession!=defaultSession){
							//reset start from begining since its a new session
							currentSession=defaultSession;
							timeoutCount=0;
						}
					}
					reallyCloseSession(defaultSession);
				}
				
			}
		});
    	m.start();
    }
    
    private void setupSessionManagement(){
    	stopSessionManager();
        setSessionKeepAlive(true);
    	sessionManager=new Thread(new Runnable() {
			public void run() {
				while (!isSessionInvalid() && isSessionKeepAlive()){
					try {
						setSessionKeepAlive(false);
						Thread.sleep(SESSION_TIME_OUT);
					} catch (InterruptedException e) {
						//no issue
					}
				}
				reallyCloseSession(defaultSession);
			}
		});
    	sessionManager.start();
    }
    
    private void stopSessionManager(){
    	if (sessionManager!=null) {
			sessionManager.interrupt();
		}
    }
    protected boolean isSessionKeepAlive() {
		return sessionKeepAlive;
	}

	public JCRRegistry(Repository repo, Credentials credentials) {
        this.repository = repo;
        this.credentials = credentials;
    }

	protected Node getRootNode(Session session) throws RepositoryException {
		String ROOT_NODE_TEXT = "root";
		if (!getSessionNodes().containsKey(null) || !getSessionNodes().get(null).get(ROOT_NODE_TEXT).getSession().isLive()){
			getSessionNodes().put(null, new HashMap<String, Node>());
			getSessionNodes().get(null).put(ROOT_NODE_TEXT, session.getRootNode());
		}
		return getOrAddNode(null, ROOT_NODE_TEXT);
	}
	
	public Session getSession() throws RepositoryException {
    	if (isSessionInvalid()){
    		reallyCloseSession(defaultSession);
        	synchronized (sessionSynchronousObject) {
//	    		System.out.println("session created");
		        Session session = null;
		        try {
		            session = repository.login(credentials);
		            if (session == null) {
		                session = resetSession(session);
		            }
		        } catch (Exception e) {
		            session = resetSession(session);
		        }
		        defaultSession=session;
				if (defaultSession!=null) {
					defaultSession
							.getWorkspace()
							.getObservationManager()
							.addEventListener(
									getWorkspaceChangeEventListener(),
									Event.NODE_ADDED | Event.NODE_REMOVED
											| Event.NODE_MOVED | Event.PROPERTY_CHANGED | Event.PROPERTY_ADDED | Event.PROPERTY_REMOVED, "/", true,
									null, null, false);
					currentSessionUseCount.put(session, 1);
				}
        	}
	        setupSessionManagement();
    	}else{
            setSessionKeepAlive(true);
            synchronized (sessionSynchronousObject) {
		        currentSessionUseCount.put(defaultSession, currentSessionUseCount.get(defaultSession)+1);
        	}
    	}
        return defaultSession;
    }

    protected Session resetSession(Session session){
        try {
            Constructor c = registryRepositoryFactory.getConstructor();
            RepositoryFactory repositoryFactory = (RepositoryFactory) c.newInstance();
            setRepositoryURI(repositoryURI);
            repository = repositoryFactory.getRepository(connectionMap);
            setUsername(username);
            credentials = new SimpleCredentials(getUsername(), getPassword().toCharArray());
            session = repository.login(credentials);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (InstantiationException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (IllegalAccessException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (InvocationTargetException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (RepositoryException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        return session;
    }

    protected Node getOrAddNode(Node node, String name) throws RepositoryException {
    	Map<Node, Map<String, Node>> sessionNodes = getSessionNodes();
    	if (sessionNodes.containsKey(node)){
    		if (sessionNodes.get(node)!=null && sessionNodes.get(node).containsKey(name)){
    			if (sessionNodes.get(node).get(name).getSession().isLive()){
    				return sessionNodes.get(node).get(name);
    			}
    		}
    	}else{
    		sessionNodes.put(node,new HashMap<String, Node>());
    	}
        Node node1 = null;
        try {
            node1 = node.getNode(name);
        	sessionNodes.get(node).put(name, node1);
        } catch (PathNotFoundException pnfe) {
            node1 = node.addNode(name);
        } catch (RepositoryException e) {
            String msg = "failed to resolve the path of the given node ";
            log.debug(msg);
            throw new RepositoryException(msg, e);
        }
{'fraction_non_alphanumeric': 0.09950955085183273, 'fraction_numerical': 0.0027103768714506968, 'mean_word_length': 2.759501859938541, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6967023', 'n_tokens_mistral': 7457, 'n_tokens_neox': 6130, 'n_words': 1498}