Moved JoinHelper into Metamodelhelper,

removed guava
diff --git a/core/pom.xml b/core/pom.xml
index aeee377..3af58c9 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -32,10 +32,6 @@
 			<artifactId>slf4j-api</artifactId>
 		</dependency>
 		<dependency>
-			<groupId>com.google.guava</groupId>
-			<artifactId>guava</artifactId>
-		</dependency>
-		<dependency>
 			<groupId>org.slf4j</groupId>
 			<artifactId>slf4j-nop</artifactId>
 			<scope>test</scope>
diff --git a/core/src/main/java/org/apache/metamodel/JoinHelper.java b/core/src/main/java/org/apache/metamodel/JoinHelper.java
deleted file mode 100644
index c8cdfa7..0000000
--- a/core/src/main/java/org/apache/metamodel/JoinHelper.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- * 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.metamodel;
-
-import com.google.common.collect.Lists;
-import org.apache.metamodel.data.*;
-import org.apache.metamodel.query.FilterItem;
-import org.apache.metamodel.query.SelectItem;
-
-import java.util.*;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-
-/**
- * Join Execution and related methods.
- */
-public abstract class JoinHelper {
-
-
-    /**
-     * Executes a simple nested loop join. The innerLoopDs will be copied in an in-memory dataset.
-     *
-     * @param outerLoopDs
-     * @param innerLoopDs
-     * @param filters
-     * @return
-     */
-    public static InMemoryDataSet nestedLoopJoin( DataSet innerLoopDs,  DataSet outerLoopDs, Collection<FilterItem> filters){
-
-        List<Row> innerRows = innerLoopDs.toRows();
-
-
-        List<SelectItem> innerSelItems = Lists.newArrayList(innerLoopDs.getSelectItems());
-        List<SelectItem> outerSelItems = Lists.newArrayList(outerLoopDs.getSelectItems());
-        List<SelectItem> allItems = Lists.newArrayList(innerSelItems);
-        allItems.addAll(outerSelItems);
-
-
-        Set<FilterItem> filterAll = applicableFilters(filters, allItems);
-
-
-        DataSetHeader jointHeader = joinHeader(outerLoopDs, innerLoopDs);
-
-        List<Row> resultRows = Lists.newArrayList();
-        for(Row outerRow: outerLoopDs){
-            for(Row innerRow: innerRows){
-                Row joinedRow =  joinRow(outerRow,innerRow,jointHeader);
-                if(filterAll.isEmpty()|| filterAll.stream().allMatch(fi -> fi.accept(joinedRow))){
-                    resultRows.add(joinedRow);
-                }
-            }
-        }
-
-
-
-        return new InMemoryDataSet(jointHeader,resultRows);
-    }
-
-
-    public static  Set<FilterItem> applicableFilters(Collection<FilterItem> filters, Collection<SelectItem> selectItemList) {
-
-        Set<SelectItem> items = new HashSet<>(selectItemList);
-
-        return filters.stream().filter( fi -> {
-            Collection<SelectItem> fiSelectItems = Lists.newArrayList(fi.getSelectItem());
-            Object operand = fi.getOperand();
-            if(operand instanceof SelectItem){
-                fiSelectItems.add((SelectItem) operand);
-            }
-
-            return items.containsAll(fiSelectItems);
-
-        }).collect(Collectors.toSet());
-    }
-
-
-
-
-
-    /**
-     * joins two datasetheader.
-     * @param ds1 the headers for the left
-     * @param ds2 the tright headers
-     * @return
-     */
-    public static DataSetHeader joinHeader(DataSet ds1, DataSet ds2){
-        List<SelectItem> joinedSelectItems = Lists.newArrayList(ds1.getSelectItems());
-        joinedSelectItems.addAll(Lists.newArrayList(ds2.getSelectItems()));
-        return  new CachingDataSetHeader(joinedSelectItems);
-
-
-    }
-
-    /**
-     * Joins two rows into one.
-     *
-     * Consider parameter ordering to maintain backwards compatbility
-     *
-     * @param row1 the tuples, that will be on the left
-     * @param row2 the tuples, that will be on the right
-     * @param jointHeader
-     * @return
-     */
-    public static Row joinRow(Row row1, Row row2, DataSetHeader jointHeader){
-        Object[] joinedRow = new Object[row1.getValues().length + row2.getValues().length];
-
-        System.arraycopy(row1.getValues(),0,joinedRow,0,row1.getValues().length);
-        System.arraycopy(row2.getValues(),0,joinedRow,row1.getValues().length,row2.getValues().length);
-
-
-        return new DefaultRow(jointHeader,joinedRow);
-
-
-    }
-
-
-}
diff --git a/core/src/main/java/org/apache/metamodel/MetaModelHelper.java b/core/src/main/java/org/apache/metamodel/MetaModelHelper.java
index c788633..f30a08a 100644
--- a/core/src/main/java/org/apache/metamodel/MetaModelHelper.java
+++ b/core/src/main/java/org/apache/metamodel/MetaModelHelper.java
@@ -20,8 +20,8 @@
 
 import java.util.*;
 import java.util.Map.Entry;
+import java.util.stream.Collectors;
 
-import com.google.common.collect.Lists;
 import org.apache.metamodel.data.CachingDataSetHeader;
 import org.apache.metamodel.data.DataSet;
 import org.apache.metamodel.data.DataSetHeader;
@@ -39,7 +39,6 @@
 import org.apache.metamodel.query.FilterItem;
 import org.apache.metamodel.query.FromItem;
 import org.apache.metamodel.query.GroupByItem;
-import org.apache.metamodel.query.OperatorType;
 import org.apache.metamodel.query.OrderByItem;
 import org.apache.metamodel.query.Query;
 import org.apache.metamodel.query.ScalarFunction;
@@ -170,9 +169,10 @@
     public static DataSet getCarthesianProduct(DataSet... fromDataSets) {
         return getCarthesianProduct(fromDataSets, new FilterItem[0]);
     }
-    
-    
-    
+
+    public static DataSet getCarthesianProduct(DataSet[] fromDataSets, FilterItem... filterItems) {
+        return getCarthesianProduct(fromDataSets, Arrays.asList(filterItems));
+    }
 
     public static DataSet getCarthesianProduct(DataSet[] fromDataSets, Iterable<FilterItem> whereItems) {
         assert(fromDataSets.length>0);
@@ -181,15 +181,15 @@
             return getFiltered(fromDataSets[0], whereItems);
         }
         // do a nested loop join, no matter what
-        Iterator<DataSet> dsIter = Lists.newArrayList(fromDataSets).iterator();
+        Iterator<DataSet> dsIter = Arrays.asList(fromDataSets).iterator();
 
         DataSet joined = dsIter.next();
 
         while(dsIter.hasNext()){
-            joined = JoinHelper.nestedLoopJoin(
+            joined = nestedLoopJoin(
                     dsIter.next(),
                     joined,
-                    Lists.newArrayList(whereItems));
+                    (whereItems));
 
         }
 
@@ -198,12 +198,72 @@
 
     }
 
-    
+    /**
+     * Executes a simple nested loop join. The innerLoopDs will be copied in an in-memory dataset.
+     *
+     */
+    public static InMemoryDataSet nestedLoopJoin(DataSet innerLoopDs,  DataSet outerLoopDs, Iterable<FilterItem> filtersIterable){
 
-    public static DataSet getCarthesianProduct(DataSet[] fromDataSets, FilterItem... filterItems) {
-        return getCarthesianProduct(fromDataSets, Arrays.asList(filterItems));
+        List<FilterItem> filters = new ArrayList<>();
+        for(FilterItem fi : filtersIterable){
+            filters.add(fi);
+        }
+        List<Row> innerRows = innerLoopDs.toRows();
+
+
+        List<SelectItem> allItems = new ArrayList<>(Arrays.asList(outerLoopDs.getSelectItems())) ;
+        allItems.addAll(Arrays.asList(innerLoopDs.getSelectItems()));
+
+        Set<FilterItem> applicableFilters = applicableFilters(filters,allItems);
+
+        DataSetHeader jointHeader = new CachingDataSetHeader(allItems);
+
+        List<Row> resultRows = new ArrayList<>();
+        for(Row outerRow: outerLoopDs){
+            for(Row innerRow: innerRows){
+
+                Object[] joinedRowObjects = new Object[outerRow.getValues().length + innerRow.getValues().length];
+
+                System.arraycopy(outerRow.getValues(),0,joinedRowObjects,0,outerRow.getValues().length);
+                System.arraycopy(innerRow.getValues(),0,joinedRowObjects,outerRow.getValues().length,innerRow.getValues().length);
+
+                Row joinedRow =  new DefaultRow(jointHeader,joinedRowObjects);
+
+
+                if(applicableFilters.isEmpty()|| applicableFilters.stream().allMatch(fi -> fi.accept(joinedRow))){
+                    resultRows.add(joinedRow);
+                }
+            }
+        }
+
+        return new InMemoryDataSet(jointHeader,resultRows);
     }
 
+    /**
+     * Filters the FilterItems such that only the FilterItems are returned,
+     * which contain SelectItems that are contained in selectItemList
+     * @param filters
+     * @param selectItemList
+     * @return
+     */
+    private static  Set<FilterItem> applicableFilters(Collection<FilterItem> filters, Collection<SelectItem> selectItemList) {
+
+        Set<SelectItem> items = new HashSet<SelectItem>(selectItemList);
+
+        return filters.stream().filter( fi -> {
+            Collection<SelectItem> fiSelectItems = new ArrayList<>();
+            fiSelectItems.add(fi.getSelectItem());
+            Object operand = fi.getOperand();
+            if(operand instanceof SelectItem){
+                fiSelectItems.add((SelectItem) operand);
+            }
+
+            return items.containsAll(fiSelectItems);
+
+        }).collect(Collectors.toSet());
+    }
+
+
     public static DataSet getFiltered(DataSet dataSet, Iterable<FilterItem> filterItems) {
         List<IRowFilter> filters = CollectionUtils.map(filterItems, filterItem -> {
             return filterItem;